Merge branch 'develop' into backend/max

This commit is contained in:
Maximilian Leopold 2019-04-13 14:28:32 +02:00
commit 0de405167b
25 changed files with 876 additions and 297 deletions

3
.gitignore vendored
View File

@ -85,6 +85,9 @@ gradle-app.setting
# Cache of project # Cache of project
.gradletasknamecache .gradletasknamecache
# Node
node_modules/
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties # gradle/wrapper/gradle-wrapper.properties

View File

@ -43,7 +43,7 @@ dependencies {
//ompile group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '1.2.0.RELEASE' //ompile group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '1.2.0.RELEASE'
compile group: 'org.springframework.security', name: 'spring-security-core', version: '5.1.4.RELEASE' compile group: 'org.springframework.security', name: 'spring-security-core', version: '5.1.4.RELEASE'
compile group: 'at.favre.lib', name: 'bcrypt', version: '{latest-version}' //compile group: 'at.favre.lib', name: 'bcrypt', version: '{latest-version}'
//JWT //JWT
compile 'io.jsonwebtoken:jjwt-api:0.10.5' compile 'io.jsonwebtoken:jjwt-api:0.10.5'

View File

@ -22,6 +22,7 @@
</q-header> </q-header>
<q-drawer <q-drawer
side="left"
v-model="leftDrawerOpen" v-model="leftDrawerOpen"
bordered bordered
show-if-above show-if-above
@ -58,11 +59,10 @@
</q-item> </q-item>
<q-item <q-item
clickable clickable
disable
class="text-primary" class="text-primary"
v-ripple v-ripple
tag="a" tag="a"
to="/" to="/ranking"
> >
<q-item-section avatar> <q-item-section avatar>
<q-icon name="list"/> <q-icon name="list"/>
@ -73,11 +73,10 @@
</q-item> </q-item>
<q-item <q-item
clickable clickable
disable
class="text-primary" class="text-primary"
v-ripple v-ripple
tag="a" tag="a"
to="/Login" to="/Profile"
> >
<q-item-section avatar> <q-item-section avatar>
<q-icon name="perm_identity"/> <q-icon name="perm_identity"/>

View File

@ -1,43 +1,60 @@
<template> <template>
<div> <div>
<!-- <div :is="stationComponent" @q-tb="scrollToBottomState" :stationObject="tempStation">STATION</div>-->
<!-- <div v-show="!stationComponent">-->
<form> <form>
<div class="q-pa-md q-gutter-y-md"> <div class="q-pa-md q-gutter-y-md">
<p class="text-h5">Cache erstellen/bearbeiten</p> <p class="text-h5">{{ isNewCache ? "Neuen Cache erstellen" : "Cache bearbeiten"}}</p>
<q-input class="col" dense stack-label filled v-model="text" label="Name"/> <q-input class="col" dense stack-label filled v-model="tempCache.name" label="Name" @change="cacheToStore"/>
<q-input <q-input
v-model="description" v-model="tempCache.description"
dense dense
stack-label stack-label
filled filled
autogrow autogrow
type="textarea" type="textarea"
label="Beschreibung" label="Beschreibung"
@change="cacheToStore"
/>
<q-input class="col" dense stack-label filled v-model="tempCache.rankingPoints" label="Punktewert"
@change="cacheToStore"/>
<q-input
disable
v-model="tempCache.reward"
dense
stack-label
filled
autogrow
type="textarea"
label="Belohnung"
@change="cacheToStore"
/> />
<q-input class="col" dense stack-label filled v-model="text" label="Punktewert"/>
<p class="text-h6">Stationen</p> <p class="text-h6">Stationen</p>
<q-list bordered separator class="rounded-borders"> <q-list bordered separator class="rounded-borders">
<q-item> <q-item v-for="(station, index) in cache.stationen" :key="index">
<q-item-section avatar> <q-item-section avatar>
<q-avatar color="primary" text-color="white"> <q-avatar color="primary" text-color="white">
1 {{ index + 1 }}
</q-avatar> </q-avatar>
</q-item-section> </q-item-section>
<q-item-section top> <q-item-section top>
<q-item-label lines="1"> <q-item-label lines="1">
<!--<span class="text-weight-medium">[quasarframework/quasar]</span>--> <span class="text-grey-8">ID: {{ station.id ? station.id : "keine" }}</span>
<span class="text-grey-8">Beschreibung:</span>
</q-item-label> </q-item-label>
<q-item-label lines="1" class="q-mt-xs text-body2"> <q-item-label lines="1" class="q-mt-xs text-body2">
<span class="cursor-pointer">Dies ist der Anfang der Beschreibung...</span> <span class="cursor-pointer">{{ station.description }}</span>
</q-item-label>
<q-item-label caption lines="1">
Code: {{ station.code }}
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
<q-item-section side> <q-item-section side>
<div class="text-grey-8 q-gutter-xs"> <div class="text-grey-8 q-gutter-xs">
<q-btn class="" color="" flat dense round icon="delete" /> <q-btn @click="deleteStation(index)" class="" color="" flat dense round icon="delete"/>
<q-btn class="" color="" flat dense round icon="edit" /> <q-btn @click="editStation(index)" class="" color="" flat dense round icon="edit"/>
</div> </div>
</q-item-section> </q-item-section>
</q-item> </q-item>
@ -47,28 +64,122 @@
<q-btn @click="addStation" unelevated color="primary" label="Station hinzufügen" icon-right="add"/> <q-btn @click="addStation" unelevated color="primary" label="Station hinzufügen" icon-right="add"/>
</div> </div>
<div class="row q-mt-xl"> <div class="row q-mt-xl">
<q-btn @click="saveCache" class="full-width" unelevated stack color="positive" label="Cache speichern" icon="save_alt"/> <q-btn @click="saveCache" class="full-width" color="primary" unelevated stack label="Cache speichern"
icon="save_alt"/>
</div> </div>
</div> </div>
</form> </form>
<!-- </div>-->
</div> </div>
</template> </template>
<script> <script>
// import station from './StationEdit'
import {mapGetters} from 'vuex';
export default { export default {
name: "Cache", name: "Cache",
data() { data() {
return { return {
text: "" // stationComponent: null,
scrolldown: false,
isNewCache: this.$route.params.id === undefined,
tempCache: {},
} }
}, },
// components: {
// station
// },
beforeCreate: function () {
},
created: function () {
console.log("isNewCache: " + this.isNewCache);
console.log("fetch Caches from Store");
this.tempCache = JSON.parse(JSON.stringify(this.cache));
},
beforeMount: function () {
},
mounted: function () {
console.log("Scrolldown: " + this.scrolldown)
},
updated: function () {
if (this.scrolldown) {
console.log("scroll down...");
window.scrollTo(0, document.body.scrollHeight);
this.scrolldown = false
}
//this.SET_CACHE(this.tempCache);
//this.scrollToBottom();
},
methods: { methods: {
// ...mapMutations([
// 'cacheCollector/SET_CACHE',
// 'cacheCollector/ADD_STATION',
// 'cacheCollector/REMOVE_STATION',
// 'cacheCollector/RESET_NEW_CACHE',
// 'cacheCollector/LOAD_REMOTE_CACHE'
// ]),
// swapComponent: function (component) {
// this.stationComponent = component;
// },
cacheToStore() {
// push tempCache to Store
console.log("set Cache");
this.$store.commit('cacheCollector/SET_CACHE', JSON.parse(JSON.stringify(this.tempCache)));
// this.SET_CACHE(JSON.parse(JSON.stringify(this.tempCache)));
},
addStation() { addStation() {
this.$router.push({ path: '/station' });
//this.swapComponent(station);
// create Station and add it to array tempCache.stationen
},
editStation(index) {
console.log("editStation("+index+")");
const station = this.cache.stationen[index];
console.log(station)
if (station.hasOwnProperty('id') ) {
//this.$router.push({ path: '/station/'+station.id});
} else {
// TODO Stationen bearbeitbar machen bevor sie abgeschickt werden. Am besten Station Objekt als Übergabe Parameter bei Router
this.$store.commit('cacheCollector/SET_TEMPSTATION', station);
this.$router.push({ path: `/station-l/${index}` }); // add parameter
}
},
deleteStation(index) {
// TODO wenn Station id hat, mit Backend abgleichen
this.$store.commit('cacheCollector/REMOVE_STATION', index);
}, },
saveCache() { saveCache() {
// commit to store, send to api, if success -> reset store
if (this.isNewCache) {
console.log(this.cache);
console.log(JSON.stringify(this.cache));
this.$axios.post('http://localhost:8080/api/createCache', this.cache)
.then((response) => {
console.log("POST api/createCache: " + response.statusText);
this.$store.commit('cacheCollector/RESET_NEW_CACHE');
this.$router.push({ path: '/overview' });
})
.catch((error) => {
});
} else {
// TODO update existing Cache
} }
},
},
computed: {
...mapGetters({
cache: 'cacheCollector/GET_CACHE'
}),
// computedCache: {
// set(value) {
// console.log("set cache")
// },
// get() {
// console.log("get cache");
// return this.$store.getters.cacheCollector.GET_CACHE
// }
// }
} }
} }
</script> </script>

View File

@ -5,7 +5,7 @@
</p> </p>
<p class="text-faded">Sorry, nothing here...<strong>(404)</strong></p> <p class="text-faded">Sorry, nothing here...<strong>(404)</strong></p>
<q-btn color="secondary" style="width:200px;" @click="$router.push('/')" <q-btn color="secondary" style="width:200px;" @click="$router.push('/')"
>Go back</q-btn >Zur Startseite</q-btn
> >
</div> </div>
</template> </template>

View File

@ -6,14 +6,16 @@
<div class="col"> <div class="col">
<div class=""> <div class="">
<div class="" style="max-width: 440px"> <div class="" style="max-width: 440px">
<q-input outlined filled stack-label v-model="user.username" type="text" label="Benutzername" autocomplete="username"/> <q-input outlined filled stack-label v-model="user.username" type="text" label="Benutzername"
autocomplete="username"/>
</div> </div>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class=""> <div class="">
<div class="" style="max-width: 440px"> <div class="" style="max-width: 440px">
<q-input outlined filled stack-label v-model="user.password" type="password" label="Passwort" autocomplete="current-password"/> <q-input outlined filled stack-label v-model="user.password" type="password" label="Passwort"
autocomplete="current-password"/>
</div> </div>
</div> </div>
</div> </div>
@ -58,7 +60,8 @@
<q-btn flat label="OK" color="red-9" v-close-popup/> <q-btn flat label="OK" color="red-9" v-close-popup/>
</q-card-actions> </q-card-actions>
</q-card> </q-card>
</q-dialog> </div> </q-dialog>
</div>
</template> </template>
<script> <script>
@ -86,11 +89,15 @@
}, },
computed: { computed: {
userAuthenticated() { userAuthenticated() {
return this.$store.state.auth.userAuthenticated.isAuthenticated console.log("login: userAuthenticated()")
// console.log(this.$store.getters['auth/IS_AUTHENTICATED']);
// return this.$store.getters['auth/IS_AUTHENTICATED']
return this.$store.state.auth.isAuthenticated;
} }
}, },
methods: { methods: {
login: function () { login: function () {
const data = { const data = {
username: this.user.username, username: this.user.username,
password: this.user.password password: this.user.password
@ -112,22 +119,23 @@
}, },
evalAuthentication: function () { evalAuthentication: function () {
this.$store.commit('auth/SET_AUTHENTICATED'); this.$store.commit('auth/SET_AUTHENTICATED');
this.$store.commit('auth/SET_USER');
}, },
logout: function () { logout: function () {
console.log("logout()"); console.log("logout()");
console.log(JSON.parse(localStorage.getItem('userToken'))); console.log(JSON.parse(localStorage.getItem('userToken')));
this.$axios.get('http://localhost:8080/api/logout', { // this.$axios.get('http://localhost:8080/api/logout', {
params: { // params: {
token: JSON.parse(localStorage.getItem('userToken')) // token: JSON.parse(localStorage.getItem('userToken'))
} // }
}) // })
.then((response) => { // .then((response) => {
console.log("GET/POST http://localhost:8080/api/logout/ - response: " + response.data); // console.log("GET/POST http://localhost:8080/api/logout/ - response: " + response.data);
// })
// .catch((error) => {
// });
localStorage.removeItem('userToken'); localStorage.removeItem('userToken');
this.evalAuthentication(); this.evalAuthentication();
})
.catch((error) => {
});
}, },
}, },
}; };

View File

@ -44,20 +44,29 @@
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item class="q-pr-sm reverse q-gutter-x-sm"> <q-item class="q-pr-sm reverse q-gutter-x-sm">
<q-btn @click="startCache(cache.id)" unelevated color="positive" stack icon="arrow_forward" label="Starten" size="sm"/> <q-btn @click="startCache(cache.id)" unelevated color="positive" stack icon="arrow_forward"
<q-btn v-if="hasAdminState" @click="startCache(cache.id)" unelevated color="amber" stack icon="edit" label="Bearbeiten" size="sm"/> label="Starten" size="sm"/>
<q-btn v-if="hasAdminState" @click="startCache(cache.id)" unelevated color="negative" stack icon="delete" label="Löschen" size="sm"/> <q-btn disable v-if="hasAdminState" @click="editCache(cache.id)" unelevated color="amber" stack
icon="edit" label="Bearbeiten" size="sm"/>
<q-btn v-if="hasAdminState" @click="deleteCache(cache.id)" unelevated color="negative" stack
icon="delete" label="Löschen" size="sm"/>
</q-item> </q-item>
</q-expansion-item> </q-expansion-item>
</q-card> </q-card>
</q-list> </q-list>
<div v-if="hasAdminState" class="row">
<q-btn @click="addCache" unelevated color="primary" stack icon="add" label="Neuer Cache"
class="full-width"/>
</div>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="map" class="q-pa-none fit"> <q-tab-panel name="map" class="q-pa-none fit">
<!--<div class="full-width full-height absolute-full" style="background: url('statics/osm_mock.png'); background-size: cover">--> <!--<div class="full-width full-height absolute-full" style="background: url('statics/osm_mock.png'); background-size: cover">-->
<!--</div>--> <!--</div>-->
<q-img src="https://www.buga2019.de/we-bilder/3.Gartenausstellung/Gelaendeplan/190320_Gelaendeplan-quadratisch.jpg" transition="fade" class="absolute-full"> <q-img
src="https://www.buga2019.de/we-bilder/3.Gartenausstellung/Gelaendeplan/190320_Gelaendeplan-quadratisch.jpg"
transition="fade" class="absolute-full">
<template v-slot:loading> <template v-slot:loading>
<q-spinner-puff color="cyan-14" size="4em"/> <q-spinner-puff color="cyan-14" size="4em"/>
</template> </template>
@ -65,6 +74,22 @@
</q-tab-panel> </q-tab-panel>
</q-tab-panels> </q-tab-panels>
<q-dialog v-model="dialog" persistent transition-show="scale" transition-hide="scale">
<q-card class="bg-red-9 text-white" style="">
<q-card-section>
<div class="text-h6">Fehler</div>
</q-card-section>
<q-card-section>
{{ dialogMsg }}
</q-card-section>
<q-card-actions align="right" class="bg-white text-teal">
<q-btn flat label="OK" color="red-9" v-close-popup/>
</q-card-actions>
</q-card>
</q-dialog>
</div> </div>
</q-page> </q-page>
@ -77,28 +102,31 @@
*/ */
</style> </style>
<script> <script>
//import {dom} from 'quasar'
//const {height, width} = dom
export default { export default {
data() { data() {
return { return {
tab: 'list', tab: 'list',
// hheight: 71.0,
// fheight: 36.0, //37
//header: {h: '0px', w: 0}
caches: [], caches: [],
dialog: false,
dialogMsg: "",
} }
}, },
mounted: function () { mounted: function () {
}, },
computed: { computed: {
// ...mapGetters([
// 'auth/GET_ADMINSTATE'
// ]),
hasAdminState() { hasAdminState() {
return this.$store.state.auth.userAuthenticated.isAdmin return this.$store.getters['auth/GET_ADMINSTATE'];
} }
}, },
created: function () { created: function () {
console.log("created(): " + this.caches); console.log("created(): " + this.caches);
this.fetchAllCaches(); this.fetchAllCaches();
this.$store.commit('auth/SET_AUTHENTICATED');
this.$store.commit('auth/SET_USER');
}, },
methods: { methods: {
fetchAllCaches() { fetchAllCaches() {
@ -108,6 +136,18 @@
this.caches = response.data; this.caches = response.data;
}) })
}, },
addCache() {
this.$router.push({path: `/cache`})
},
editCache() {
},
deleteCache(id) {
console.log('delete cache: ' + id)
this.$axios.delete('http://localhost:8080/api/deleteCache', {params: {cacheID: id}})
.then((response) => {
this.fetchAllCaches()
})
},
startCache(cacheID) { startCache(cacheID) {
const userToken = JSON.parse(localStorage.getItem('userToken')); const userToken = JSON.parse(localStorage.getItem('userToken'));
let params = {cacheID: cacheID}; let params = {cacheID: cacheID};
@ -118,10 +158,12 @@
this.$axios.get('http://localhost:8080/api/startCache', {params}) this.$axios.get('http://localhost:8080/api/startCache', {params})
.then((response) => { .then((response) => {
console.log("Angefangen: " + response.data); console.log(response.data);
let stationID = response.data.aktuelleStation.id; // TODO wenn cache angefangen, dann suche die letzte gefundene Station
let stationID = this.caches.find(x => x.id === cacheID).stationen[0].id;
console.log(stationID); console.log(stationID);
this.$router.push({ path: `/station/${stationID}` }) //this.$router.push({path: `/station/${stationID}`})
this.$router.push({path: `/station/${cacheID}/${stationID}`})
}) })
} }
} }

View File

@ -0,0 +1,136 @@
<template>
<q-page class="column no-wrap">
<div class="bg-red col col-shrink" style="">
<q-tabs
v-model="tab"
class="bg-grey-2"
inline-label
align="justify"
active-bg-color="bg-grey-1"
active-color="cyan-14"
indicator-color="cyan-14"
switch-indicator
>
<q-tab name="profile" label="Profil" icon="perm_identity"/>
<q-tab name="startedCaches" label="Angefangene Caches" icon="playlist_play"/>
<q-tab name="finishedCaches" label="Beendete Caches" icon="playlist_add_check"/>
</q-tabs>
<q-separator color="grey-4"/>
</div>
<div class="col flex column">
<q-tab-panels v-model="tab" animated swipeable class="col">
<q-tab-panel name="profile" class=" fit">
</q-tab-panel>
<q-tab-panel name="startedCaches" class=" fit">
<q-list>
<q-card class="q-mb-md" v-for="startedCache in startedCaches" :key="startedCache.id">
<q-expansion-item
class=""
v-if="startedCache.cacheAccesDefinition.description == 'angefangen'"
expand-icon-toggle
expand-separator
icon="location_on"
:label="startedCache.cache.name"
:caption=" startedCache.cache.description"
>
<q-item>
<q-item-section top avatar class="self-center">
<!--<q-icon rounded color="cyan-14" name="location_on" size="3rem"/>-->
</q-item-section>
<q-item-section>
<q-item-label caption>{{'Nächste Aufgabe: ' + startedCache.aktuelleStation.description }}
</q-item-label>
<q-item-label caption>{{'Ranglistenpunkte für diesen Cache: ' + startedCache.cache.rankingPoints}}
</q-item-label>
</q-item-section>
<q-item-section side top class="self-center">
</q-item-section>
</q-item>
<q-item class="q-pr-sm reverse q-gutter-x-sm">
<q-btn @click="startCache(startedCache.id)" unelevated color="positive" stack icon="arrow_forward"
label="Fortfahren" size="sm"/>
</q-item>
</q-expansion-item>
</q-card>
</q-list>
</q-tab-panel>
<q-tab-panel name="finishedCaches" class="fit">
<q-list>
<q-card class="q-mb-md" v-for="startedCache in startedCaches" :key="startedCache.id">
<q-expansion-item
class=""
v-if="startedCache.cacheAccesDefinition.description == 'abgeschlossen'"
expand-icon-toggle
expand-separator
icon="location_on"
:label="startedCache.cache.name"
:caption=" startedCache.cache.description"
>
<q-item>
<q-item-section top avatar class="self-center">
<!--<q-icon rounded color="cyan-14" name="location_on" size="3rem"/>-->
</q-item-section>
<q-item-section>
<q-item-label caption>{{'Erhaltene Punkte für diesen Cache: ' + startedCache.cache.rankingPoints }}</q-item-label>
</q-item-section>
<q-item-section side top class="self-center">
</q-item-section>
</q-item>
</q-expansion-item>
</q-card>
</q-list>
</q-tab-panel>
</q-tab-panels>
</div>
</q-page>
</template>
<style>
/*
.my-list-card-item
padding-left: 8px
*/
</style>
<script>
//import {dom} from 'quasar'
//const {height, width} = dom
export default {
data() {
return {
tab: 'startedCaches' + 'finishedCaches',
startedCaches: [],
}
},
mounted: function () {
},
computed: {
hasAdminState() {
return this.$store.getters['auth/GET_ADMINSTATE'];
}
},
created: function() {
this.fetchUserCaches();
this.$store.commit('auth/SET_AUTHENTICATED');
this.$store.commit('auth/SET_USER');
},
methods: {
fetchUserCaches: function() {
const token = JSON.parse(localStorage.getItem('userToken'));
this.$axios.get('http://localhost:8080/api/getMyCaches', { params: {token}} )
.then((response) => {
this.startedCaches = response.data;
});
},
continueCache(cacheID) {
}
}
}
</script>

View File

@ -26,9 +26,9 @@
</div> </div>
<p class="text-h6 q-mt-md">Lösung</p> <p class="text-h6 q-mt-md">Lösung</p>
<q-input class="col" dense stack-label filled v-model="station.solution" label="Lösung" /> <q-input class="col" dense stack-label filled v-model="station.solution" label="Lösung" />
<q-input class="col q-mt-md" dense stack-label filled v-model="station.code" label="Code" readonly/> <!-- <q-input class="col q-mt-md" dense stack-label filled v-model="station.code" label="Code" readonly/>-->
<div class="row reverse q-mt-md q-gutter-x-md"> <div class="row reverse q-mt-md q-gutter-x-md">
<q-btn @click="addStation" unelevated color="primary" label="Speichern" icon-right="add"/> <q-btn @click="saveStation" unelevated color="primary" label="Speichern" icon-right="add"/>
<q-btn @click="dismiss" unelevated color="negative" label="verwerfen" icon-right="delete"/> <q-btn @click="dismiss" unelevated color="negative" label="verwerfen" icon-right="delete"/>
</div> </div>
@ -36,35 +36,46 @@
</template> </template>
<script> <script>
import {mapGetters} from 'vuex';
export default { export default {
name: "Station", name: "Station",
data() { data() {
return { return {
description: "Rätsel, Aufgabe und Informationen zur Station.", description: "Rätsel, Aufgabe und Informationen zur Station.",
text:"v-model !!",
latlang: "", latlang: "",
station: { station: {
description: "description", description: "Beschreibung",
lattitude: 0.06470, lattitude: "0.000",
longitude: 0.05551, longitude: "0.000",
solution: "solution", solution: "",
code: 357547 code: ""
}, },
isNewStation: true,
// stationObject: null,
} }
}, },
// props: [ 'stationObject' ],
created: function() { created: function() {
this.isNewStation = (this.$route.params.pos === undefined);
console.log("neu: "+this.isNewStation);
console.log("pos: "+this.$route.params.pos);
console.log(this.$route);
console.log(this.station);
if (!this.isNewStation) {
this.station = JSON.parse(JSON.stringify(this.tempStation));
}
console.log(this.station);
}, },
beforeMount: function() { beforeMount: function() {
}, },
mounted: function() { mounted: function() {
console.log("'id' from url: "+this.$route.params.id);
this.concatLatlang(); this.concatLatlang();
}, },
computed: { computed: {
// concatLatlang() { ...mapGetters({
// return this.station.lattitude+", "+this.station.longitude tempStation: 'cacheCollector/GET_TEMPSTATION'
// } }),
}, },
methods: { methods: {
separateLatlang() { separateLatlang() {
@ -79,11 +90,21 @@
concatLatlang() { concatLatlang() {
this.latlang = this.station.lattitude+", "+this.station.longitude; this.latlang = this.station.lattitude+", "+this.station.longitude;
}, },
addStation() { saveStation() {
console.log("saveStation(): ");
console.log(this.station);
if (this.isNewStation) {
this.$store.commit('cacheCollector/ADD_STATION', this.station);
} else {
this.$store.commit('cacheCollector/EDIT_STATION', { index: this.$route.params.pos, station: this.station });
this.$store.commit('cacheCollector/SET_TEMPSTATION', null);
}
this.$router.push({ path: `/cache` });
console.log("station saved..");
}, },
dismiss() { dismiss() {
this.$store.commit('cacheCollector/SET_TEMPSTATION', null);
this.$router.push({ path: `/cache` });
} }
} }
} }

View File

@ -7,7 +7,8 @@
></q-img> ></q-img>
<div class="q-ma-md"> <div class="q-ma-md">
<p class="text-h4">{{ data.cacheName }}</p> <p class="text-h4">{{ data.cacheName }}</p>
<p class="text-h5">Station {{ data.station.position }}</p> <p class="text-h5">Station {{ showCacheProgress }}</p>
<!-- <p class="text-h5">Station {{ data.station.position }}</p>-->
<p>{{ data.station.description }}</p> <p>{{ data.station.description }}</p>
<!--<q-input--> <!--<q-input-->
<!--v-model="description"--> <!--v-model="description"-->
@ -32,12 +33,11 @@
data() { data() {
return { return {
code: "", code: "",
cache: null,
data: { data: {
cacheId: 22, cacheId: 22,
cacheName: "Wasserfall Cache", cacheName: "Wasserfall Cache",
nextStationId: 44,
station: { station: {
position: 1,
id: 22, id: 22,
description: "Ein kleines winterliches Schlaginstrument. Welche Blume ist damit gemeint?", description: "Ein kleines winterliches Schlaginstrument. Welche Blume ist damit gemeint?",
longitude: 9.206628, longitude: 9.206628,
@ -49,14 +49,46 @@
} }
}, },
created: function () { created: function () {
console.log("StationView: ")
console.log("'id' from url: " + this.$route.params.id)
console.log("'cache' from url: " + this.$route.params.cache)
this.fetchData();
}, },
beforeMount: function () { beforeMount: function () {
}, },
mounted: function () { mounted: function () {
console.log("'id' from url: " + this.$route.params.id)
}, },
computed: {}, computed: {
methods: {} showCacheProgress() {
let stationCount = this.cache.stationen.length;
let stationPos = 1 + this.cache.stationen.findIndex(station => station.id === Number(this.$route.params.id));
return `${stationPos} von ${stationCount}`;
}
},
methods: {
fetchData() {
this.$axios.get('http://localhost:8080/api/allCaches')
.then((response) => {
console.log("http://localhost:8080/api/allCaches");
console.log(JSON.stringify(this.data));
console.log(this.data);
console.log(response.data);
const cache = response.data.find(cache => cache.id === Number(this.$route.params.cache));
this.data.cacheId = cache.id;
this.data.cacheName = cache.name;
this.cache = cache;
console.log(JSON.stringify(this.data));
this.$axios.get('http://localhost:8080/api/getAllStations')
.then((response) => {
console.log("http://localhost:8080/api/getAllStations");
console.log(response.data);
const stationView = response.data.find(station => station.id === Number(this.$route.params.id));
console.log(JSON.stringify(stationView));
this.data.station = stationView;
});
});
}
}
} }
</script> </script>

View File

@ -0,0 +1,90 @@
<template>
<q-page class="column">
<div class="bg-red col col-shrink" style="">
<q-tabs
v-model="tab"
class="bg-grey-2"
inline-label
align="justify"
active-bg-color="bg-grey-1"
active-color="cyan-14"
indicator-color="cyan-14"
narrow-indicator
switch-indicator
>
<q-tab name="solo" label="Solo-Cacher" icon="person"/>
<q-tab name="team" label="Cacher-Team" icon="group"/>
</q-tabs>
<q-separator color="grey-4"/>
</div>
<div class="col flex column">
<q-tab-panels v-model="tab" animated swipeable class="col">
<q-tab-panel name="solo" class="q-pa-md fit">
<q-list>
<q-card class="q-mb-md" v-for="(user,index) in rankinglist" :key="user.id">
<q-item class="q-pr-sm ">
<q-item-section>
<q-item-label><a class="text-black" style="text-decoration: none"><span>{{index+1}}. {{user.username}}</span></a></q-item-label>
</q-item-section>
<q-item-section side>
<span class="text-grey">{{user.rankingPointsSum}} Punkte </span>
</q-item-section>
</q-item>
</q-card>
</q-list>
</q-tab-panel>
<q-tab-panel name="team" class=" fit">
<q-list>
<q-card class="q-mb-md">
<q-item class="q-pr-sm ">
<q-item-section>
<q-item-label>Single line item</q-item-label>
</q-item-section>
<q-item-section side>
<span class="text-grey"> Punkte </span>
</q-item-section>
</q-item>
</q-card>
</q-list>
</q-tab-panel>
</q-tab-panels>
</div>
</q-page>
</template>
<style>
/*
.my-list-card-item
padding-left: 8px
*/
</style>
<script>
import {dom} from 'quasar'
const {height, width} = dom
export default {
data() {
return {
tab: 'solo',
rankinglist: []
}
},
created: function() {
console.log("created(): " + this.rankinglist);
this.fetchRankinglist();
},
methods: {
fetchRankinglist() {
this.$axios.get('http://localhost:8080/api/getRankingList')
.then((response) => {
console.log("Rankinglist: ");
console.log(response.data);
this.rankinglist = response.data;
})
}
}
}
</script>

View File

@ -5,6 +5,7 @@ const routes = [
children: [{ path: "", component: () => import("pages/Index.vue") }] children: [{ path: "", component: () => import("pages/Index.vue") }]
}, },
{ {
path: "/overview/", path: "/overview/",
component: () => import("layouts/MyLayout.vue"), component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/Overview.vue") }] children: [{ path: "", component: () => import("pages/Overview.vue") }]
@ -14,20 +15,41 @@ const routes = [
component: () => import("layouts/MyLayout.vue"), component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/Cache.vue") }] children: [{ path: "", component: () => import("pages/Cache.vue") }]
}, },
{
path: "/cache/:id",
component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/Cache.vue") }]
},
{ {
path: "/station/", path: "/station/",
component: () => import("layouts/MyLayout.vue"), component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/StationEdit.vue") }] children: [{ path: "", component: () => import("pages/StationEdit.vue") }]
}, },
{ {
path: "/station/:id", path: "/station/:cache/:id",
component: () => import("layouts/MyLayout.vue"), component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/StationView.vue") }] children: [{ path: "", component: () => import("pages/StationView.vue") }]
}, },
{
path: "/station-l/:pos",
path: "/ranking/",
component: () => import("layouts/MyLayout.vue"),
children: [{path: "", component: () => import("pages/ranking.vue")}]
},
{
path: "/station/",
component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/StationEdit.vue") }]
},
{ {
path: "/login/", path: "/login/",
component: () => import("layouts/MyLayout.vue"), component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/Login.vue") }] children: [{ path: "", component: () => import("pages/Login.vue") }]
},
{
path: "/profile/",
component: () => import("layouts/MyLayout.vue"),
children: [{ path: "", component: () => import("pages/Profile.vue") }]
} }
]; ];

View File

@ -1,4 +1,24 @@
/* /**
export function someGetter (state) { * @return {boolean}
}
*/ */
export function GET_ADMINSTATE(state) {
console.log("GET_ADMINSTATE()");
if (state.userAuthenticated !== null) {
console.log(state.userAuthenticated.roles.find(x => x.name === "admin") != null);
return state.userAuthenticated.roles.find(x => x.name === "admin") != null;
} else {
console.log(state.userAuthenticated);
return false;
}
}
// /**
// * @return {boolean}
// */
// export function IS_AUTHENTICATED(state) {
// console.log("IS_AUTHENTICATED()");
// console.log(JSON.parse(localStorage.getItem('userToken')));
// console.log(!(JSON.parse(localStorage.getItem('userToken')) === null));
// console.log(!(localStorage.getItem('userToken') === null));
// return !(localStorage.getItem('userToken') === null);
// }

View File

@ -3,16 +3,41 @@ export const SET_AUTHENTICATED = (state) => {
console.log("SET_AUTHENTICATED()"); console.log("SET_AUTHENTICATED()");
console.log(JSON.parse(localStorage.getItem('userToken'))); console.log(JSON.parse(localStorage.getItem('userToken')));
if (localStorage.getItem('userToken')) { if (localStorage.getItem('userToken')) {
state.userAuthenticated.isAuthenticated = true; state.isAuthenticated = true;
} else { } else {
state.userAuthenticated.isAuthenticated = false; state.isAuthenticated = false;
} }
}; };
export const SET_USER_PROPERTIES = (state, user) => {
console.log("SET_USER_PROPERTIES()");
console.log("still todo!");
};
export const SET_LOGOUT = (state) => { export const SET_LOGOUT = (state) => {
console.log("SET_LOGOUT()"); console.log("SET_LOGOUT()");
localStorage.removeItem('userToken');
state.userAuthenticated = null; state.userAuthenticated = null;
state.isAuthenticated = false;
console.log(localStorage.getItem('userToken'));
}; };
export const SET_USER = (state) => {
console.log("SET_USER()");
if (localStorage.getItem('userToken')) {
axios.get('http://localhost:8080/api/getUser', {
params: {
token: JSON.parse(localStorage.getItem('userToken'))
}
})
.then((response) => {
console.log("GET/POST http://localhost:8080/api/getUser - response: ");
console.log(response.data);
state.userAuthenticated = response.data;
state.isAuthenticated = true;
if (state.userAuthenticated.hasOwnProperty('password')) delete state.userAuthenticated.password;
console.log(state.userAuthenticated);
})
.catch((error) => {
console.log("Catch Block: ")
console.log(error)
});
} else {
state.isAuthenticated = false;
state.userAuthenticated = null;
}
};

View File

@ -1,12 +1,19 @@
export default { export default {
userAuthenticated: {
id: 1,
firstname: "t",
lastname: "v",
username: "mo",
email: "test@user.com",
rankingPointsSum: 345,
isAuthenticated: false, isAuthenticated: false,
isAdmin: false, userAuthenticated: null,
}, // userAuthenticated: {
// id: 1,
// firstname: "Timo",
// lastname: "Volkmann",
// username: "moximoti",
// rankingPointsSum: 0,
// email: "test@user.com",
// password: "$2a$10$c3Fo5nuUG.nlwXP94qc7qO01/UC1OL2DebEm.5zYlisKJGRhXMnqq",
// roles: [
// {
// id: 0,
// name: "admin"
// }
// ]
// },
} }

View File

@ -1,4 +1,8 @@
/* export const GET_CACHE = (state) => {
export function someGetter (state) { console.log("GET_CACHE: retrieve cache from store. ");
} return state.newCache;
*/ };
export const GET_TEMPSTATION = (state) => {
console.log("GET_TEMPSTATION: retrieve cache from store. ");
return state.tempStation;
};

View File

@ -1,4 +1,56 @@
/* export const SET_CACHE = (state, cache) => {
export function someMutation (state) { console.log("SET_CACHE: save cache to store. ")
state.newCache = cache;
};
export const SET_TEMPSTATION = (state, station) => {
console.log("SET_TEMPSTATION: add new station to cache: "+station);
state.tempStation = station;
};
export const ADD_STATION = (state, station) => {
console.log("ADD_STATION: add new station to cache: "+station);
state.newCache.stationen.push(station);
};
export const EDIT_STATION = (state, indexStation) => {
let index, station;
index = indexStation.index;
station = indexStation.station;
console.log("EDIT_STATION: "+index+" "+station);
state.newCache.stationen[index] = station;
};
export const REMOVE_STATION = (state, index) => {
console.log("REMOVE_STATION: "+index);
state.newCache.stationen.splice(index,1);
};
export const RESET_NEW_CACHE = (state) => {
state.newCache = {
name: "",
description: "",
rankingPoints: 0,
stationen: []
};
console.log("resetted new Cache");
};
export const LOAD_REMOTE_CACHE = (state, id) => {
console.log("LOAD_REMOTE_CACHE: get caches from remote");
this.$axios.get('http://localhost:8080/api/allCaches')
.then((response) => {
const allCaches = JSON.parse(response.data);
console.log("Caches: " + allCaches.length);
if (response.data === undefined || allCaches.length === 0) {
console.log("aborted processing data.");
return;
} }
*/ let cacheToSet = null;
for (let cache in allCaches) {
console.log("Cachedata: ");
console.log(cache.id);
console.log(cache.name);
if (cache.id === id) {
cacheToSet = cache;
console.log("found matching ID: setted cache to store.");
break;
}
}
});
};

View File

@ -1,3 +1,44 @@
export default { export default {
// newCache: {
name: "",
description: "",
rankingPoints: 0,
stationen: []
},
// newCache: {
// name: "Blumencache",
// description: "Dieser Cache umfasst 4 Stationen mit Rätseln rund um das Thema Blumen",
// rankingPoints: 100,
// stationen: [
// {
// description: "Ein kleines winterliches Schlaginstrument. Welche Blume ist damit gemeint?",
// longitude: 9.206628,
// lattitude: 49.147734,
// code: 213812,
// solution: "Schneeglöckchen"
// },
// {
// description: "Ein blühendes Federvieh. Welche Blume ist damit gemeint?",
// longitude: 9.206806,
// lattitude: 49.147318,
// code: 237823,
// solution: "Gänseblümchen"
// },
// {
// description: "Eine wertvolle Farbe. Welche Blume ist damit gemeint?",
// longitude: 9.207844,
// lattitude: 49.148032,
// code: 899423,
// solution: "Edelweiß"
// },
// {
// description: "Ein Zerkleinerungsgerät in der Brüllöffnung eines Raubtieres. Welche Blume ist damit gemeint?",
// longitude: 9.207649,
// lattitude: 49.150142,
// code: 347923,
// solution: "Löwenzahn"
// }
// ]
// },
tempStation: {},
} }

View File

@ -22,7 +22,8 @@ export default function (/* { ssrContext } */) {
// enable strict mode (adds overhead!) // enable strict mode (adds overhead!)
// for dev mode only // for dev mode only
strict: process.env.DEV //strict: process.env.DEV
strict: false
}) })
/* /*

View File

@ -1,7 +1,7 @@
package hhn.labsw.bugageocaching.controller; package hhn.labsw.bugageocaching.controller;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import hhn.labsw.bugageocaching.entities.*; import hhn.labsw.bugageocaching.entities.*;
import hhn.labsw.bugageocaching.exceptions.IllegalParameterException; import hhn.labsw.bugageocaching.exceptions.IllegalParameterException;
import hhn.labsw.bugageocaching.repositories.*; import hhn.labsw.bugageocaching.repositories.*;
@ -9,12 +9,17 @@ import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCrypt; import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.xml.bind.DatatypeConverter;
import java.lang.reflect.Array;
import java.security.Key;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@ -45,9 +50,6 @@ public class Controller {
@Autowired @Autowired
UserRepository userRepository; UserRepository userRepository;
@Autowired
StationReihenfolgeRepository stationReihenfolgeRepository;
private AtomicLong counter = new AtomicLong(); private AtomicLong counter = new AtomicLong();
byte[] key = new byte[64]; byte[] key = new byte[64];
@ -118,7 +120,6 @@ public class Controller {
.setSigningKey(key) .setSigningKey(key)
.parseClaimsJws(token).getBody(); .parseClaimsJws(token).getBody();
User user = userRepository.findByUsername(claims.getSubject()); User user = userRepository.findByUsername(claims.getSubject());
if (user == null) { if (user == null) {
return ResponseEntity.status(404).body("User was not found"); return ResponseEntity.status(404).body("User was not found");
@ -128,6 +129,12 @@ public class Controller {
Optional<Cache> cacheOptional = cacheRepository.findById(Integer.valueOf(cacheID)); Optional<Cache> cacheOptional = cacheRepository.findById(Integer.valueOf(cacheID));
if (cacheOptional.isPresent()) { if (cacheOptional.isPresent()) {
Cache cache = cacheOptional.get(); Cache cache = cacheOptional.get();
if (bearbeitetRepository.findByUserAndCache(user, cache) != null) {
Bearbeitet bearbeitet1 = bearbeitetRepository.findByUserAndCache(user, cache);
return ResponseEntity.status(200).body(bearbeitet1);
}
bearbeitet.setCache(cache); bearbeitet.setCache(cache);
Station startStation = cache.getStationen().get(0); Station startStation = cache.getStationen().get(0);
@ -147,7 +154,7 @@ public class Controller {
bearbeitetRepository.save(bearbeitet); bearbeitetRepository.save(bearbeitet);
return ResponseEntity.status(200).body(new Gson().toJson(bearbeitet)); return ResponseEntity.status(201).body(new Gson().toJson(bearbeitet));
} catch (ExpiredJwtException e) { } catch (ExpiredJwtException e) {
return ResponseEntity.status(400).body("JWT Token expired"); return ResponseEntity.status(400).body("JWT Token expired");
} catch (Exception e) { } catch (Exception e) {
@ -224,20 +231,24 @@ public class Controller {
Cache cache = optionalCache.get(); Cache cache = optionalCache.get();
for (StationReihenfolge stationReihenfolge : stationReihenfolgeRepository.findAll()) {
if (stationReihenfolge.getCache().getId() == cache.getId()) {
stationReihenfolgeRepository.delete(stationReihenfolge);
}
}
for (Bearbeitet bearbeitet : bearbeitetRepository.findAll()) { for (Bearbeitet bearbeitet : bearbeitetRepository.findAll()) {
if (bearbeitet.getCache().getId() == cache.getId()) { if (bearbeitet.getCache().getId() == cache.getId()) {
bearbeitetRepository.delete(bearbeitet); bearbeitetRepository.delete(bearbeitet);
} }
} }
ArrayList<Station> stationen = new ArrayList<>();
for (Station station : cache.getStationen()) {
stationen.add(stationRepository.findById(station.getId()).get());
}
cacheRepository.delete(cache); cacheRepository.delete(cache);
for (Station station : stationen) {
stationRepository.delete(station);
}
return ResponseEntity.status(200).body(new Gson().toJson(true)); return ResponseEntity.status(200).body(new Gson().toJson(true));
} }
@ -277,7 +288,18 @@ public class Controller {
@RequestMapping("/api/getRankingList") @RequestMapping("/api/getRankingList")
@ResponseBody @ResponseBody
public ResponseEntity getRankingList() { public ResponseEntity getRankingList() {
return ResponseEntity.status(200).body(new Gson().toJson(userRepository.getRankingList()));
List<User> sendBackUsers = new LinkedList<>();
List<Object[]> rankingUsers = userRepository.getRankingList();
for (Object[] obj : rankingUsers) {
User u = new User();
u.setId((int) obj[0]);
u.setUsername((String) obj[1]);
u.setRankingPointsSum((int) obj[2]);
sendBackUsers.add(u);
}
return ResponseEntity.status(200).body(new Gson().toJson(sendBackUsers));
} }
@CrossOrigin(origins = "http://localhost:8081") // only for dev purpose @CrossOrigin(origins = "http://localhost:8081") // only for dev purpose

View File

@ -1,53 +0,0 @@
package hhn.labsw.bugageocaching.entities;
import javax.persistence.*;
@Entity
@Table
public class StationReihenfolge {
@Id
@GeneratedValue
private int id;
@OneToOne
private Cache cache;
@OneToOne
private Station station;
@OneToOne
private Station nachfolgeStation;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Cache getCache() {
return cache;
}
public void setCache(Cache cache) {
this.cache = cache;
}
public Station getStation() {
return station;
}
public void setStation(Station station) {
this.station = station;
}
public Station getNachfolgeStation() {
return nachfolgeStation;
}
public void setNachfolgeStation(Station nachfolgeStation) {
this.nachfolgeStation = nachfolgeStation;
}
}

View File

@ -1,8 +1,11 @@
package hhn.labsw.bugageocaching.repositories; package hhn.labsw.bugageocaching.repositories;
import hhn.labsw.bugageocaching.entities.Bearbeitet; import hhn.labsw.bugageocaching.entities.Bearbeitet;
import hhn.labsw.bugageocaching.entities.Cache;
import hhn.labsw.bugageocaching.entities.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
public interface BearbeitetRepository extends JpaRepository<Bearbeitet, Integer> { public interface BearbeitetRepository extends JpaRepository<Bearbeitet, Integer> {
Bearbeitet findByUserAndCache(User user, Cache cache);
} }

View File

@ -1,7 +0,0 @@
package hhn.labsw.bugageocaching.repositories;
import hhn.labsw.bugageocaching.entities.StationReihenfolge;
import org.springframework.data.repository.CrudRepository;
public interface StationReihenfolgeRepository extends CrudRepository<StationReihenfolge, Integer> {
}

View File

@ -14,7 +14,7 @@ import java.util.List;
public interface UserRepository extends CrudRepository<User, Integer> { public interface UserRepository extends CrudRepository<User, Integer> {
User findByUsername(String username); User findByUsername(String username);
@Query(value = "SELECT u.username, u.ranking_points_sum from user u order by ranking_points_sum DESC", nativeQuery = true) @Query(value = "SELECT u.id, u.username, u.ranking_points_sum from user u order by ranking_points_sum DESC", nativeQuery = true)
List<Object[]> getRankingList(); List<Object[]> getRankingList();
} }