diff --git a/package-lock.json b/package-lock.json index 2b3a277b0ad500f297f23e6bf69cf9b26ebbf4d4..397cd62b97aab5d3cff0e92fffb4576a9a040822 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1054,6 +1054,32 @@ "to-fast-properties": "^2.0.0" } }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.30", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.30.tgz", + "integrity": "sha512-TsRwpTuKwFNiPhk1UfKgw7zNPeV5RhNp2Uw3pws+9gDAkPGKrtjR1y2lI3SYn7+YzyfuNknflpBA1LRKjt7hMg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.30", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.30.tgz", + "integrity": "sha512-E3sAXATKCSVnT17HYmZjjbcmwihrNOCkoU7dVMlasrcwiJAHxSKeZ+4WN5O+ElgO/FaYgJmASl8p9N7/B/RttA==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.30" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.14.0.tgz", + "integrity": "sha512-M933RDM8cecaKMWDSk3FRYdnzWGW7kBBlGNGfvqLVwcwhUPNj9gcw+xZMrqBdRqxnSXdl3zWzTCNNGEtFUq67Q==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.30" + } + }, + "@fortawesome/vue-fontawesome": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-2.0.0.tgz", + "integrity": "sha512-N3VKw7KzRfOm8hShUVldpinlm13HpvLBQgT63QS+aCrIRLwjoEUXY5Rcmttbfb6HkzZaeqjLqd/aZCQ53UjQpg==" + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -1744,6 +1770,17 @@ "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", "dev": true }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "optional": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, "cacache": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", @@ -1770,6 +1807,34 @@ "unique-filename": "^1.1.1" } }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, "find-cache-dir": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", @@ -1791,6 +1856,25 @@ "path-exists": "^4.0.0" } }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -1855,6 +1939,16 @@ "minipass": "^3.1.1" } }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, "terser-webpack-plugin": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", @@ -1871,6 +1965,18 @@ "terser": "^4.6.12", "webpack-sources": "^1.4.3" } + }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.0.0-beta.8", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz", + "integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + } } } }, @@ -6731,6 +6837,11 @@ } } }, + "jquery": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", + "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" + }, "js-message": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz", @@ -11012,6 +11123,11 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "vee-validate": { + "version": "2.2.15", + "resolved": "https://registry.npmjs.org/vee-validate/-/vee-validate-2.2.15.tgz", + "integrity": "sha512-4TOsI8XwVkKVLkg8Nhmy+jyoJrR6XcTRDyxBarzcCvYzU61zamipS1WsB6FlDze8eJQpgglS4NXAS6o4NDPs1g==" + }, "vendors": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", @@ -11144,88 +11260,6 @@ } } }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.0.0-beta.8", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz", - "integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.1.0", - "hash-sum": "^2.0.0", - "loader-utils": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "optional": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "optional": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "vue-password": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/vue-password/-/vue-password-3.0.0.tgz", diff --git a/package.json b/package.json index f26a27c1ef635b04f7f5ccc965472b17eda9e758..901deca1328d23d51868b045cb54d1cc693075ba 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,16 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.30", + "@fortawesome/free-solid-svg-icons": "^5.14.0", + "@fortawesome/vue-fontawesome": "^2.0.0", "axios": "^0.20.0", + "bootstrap": "^4.5.2", "bootstrap-vue": "^2.17.3", "core-js": "^3.6.5", + "jquery": "^3.5.1", + "popper.js": "^1.16.1", + "vee-validate": "^2.2.15", "vue": "^2.6.11", "vue-axios-cors": "^1.0.1", "vue-router": "^3.4.3", diff --git a/src/App.vue b/src/App.vue index 22402e603f54226fa6e0fc4413f6d8a5622d2283..b90478d99b7eb1853f2baef58d880cf92e375906 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,18 +1,108 @@ <template> <div id="app"> <nav> - <router-link to="/login">Login | </router-link> - <router-link to="/home">Home</router-link> + <router-link to="/lehreruebersicht">Lehrerübersicht Archiv | </router-link> + <router-link to="/lehreruebersicht">Lehrerübersicht | </router-link> + <router-link to="/lehreruebersicht">Kursübersicht | </router-link> + <router-link to="/lehreruebersicht">Kalender | </router-link> + <router-link to="/lehreruebersicht">Vorlagen | </router-link> + + <router-link to="/register">Neuen User erstellen</router-link> + <a class="nav-link" href @click.prevent="logOut()"> + <font-awesome-icon icon="sign-out-alt" />LogOut + </a> </nav> <router-view/> </div> + <!--div id="app"> + <nav class="navbar navbar-expand navbar-dark bg-dark"> + + <a href class="navbar-brand" @click.prevent>Natlab</a> + <div class="navbar-nav mr-auto"> + <li class="nav-item"> + <router-link to="/home" class="nav-link"> + <font-awesome-icon icon="home" />Home + </router-link> + </li> + <li v-if="showAdminBoard" class="nav-item"> + <router-link to="/admin" class="nav-link">Admin Board</router-link> + </li> + <li v-if="showModeratorBoard" class="nav-item"> + <router-link to="/mod" class="nav-link">Moderator Board</router-link> + </li> + <li class="nav-item"> + <router-link v-if="currentUser" to="/user" class="nav-link">User</router-link> + </li> + </div> + + <div v-if="!currentUser" class="navbar-nav ml-auto"> + <li class="nav-item"> + <router-link to="/register" class="nav-link"> + <font-awesome-icon icon="user-plus" />Sign Up + </router-link> + </li> + <li class="nav-item"> + <router-link to="/login" class="nav-link"> + <font-awesome-icon icon="sign-in-alt" />Login + </router-link> + </li> + </div> + + <div v-if="currentUser" class="navbar-nav ml-auto"> + <li class="nav-item"> + <router-link to="/profile" class="nav-link"> + <font-awesome-icon icon="user" /> + {{ currentUser.username }} + </router-link> + </li> + <li class="nav-item"> + <a class="nav-link" href @click.prevent="logOut"> + <font-awesome-icon icon="sign-out-alt" />LogOut + </a> + </li> + </div> + </nav> + + <div class="container"> + <router-view /> + </div> + </div--> </template> <script> export default { - name: 'App' -} + computed: { + currentUser() { + return this.$store.state.auth.user; + }, + showAdminBoard() { + if (this.currentUser && this.currentUser.roles) { + return this.currentUser.roles.includes('ROLE_ADMIN'); + } + + return false; + }, + showModeratorBoard() { + if (this.currentUser && this.currentUser.roles) { + return this.currentUser.roles.includes('ROLE_MODERATOR'); + } + + return false; + } + }, + + created() { + this.$router.push("/lehreruebersicht") + }, + + methods: { + logOut: function() { + this.$store.dispatch('auth/logout'); + this.$router.push('/login'); + } + } +}; </script> diff --git a/src/components/Home.vue b/src/components/Home.vue index 95886ae03c4067c65866ef5b65cafc203b10167f..849a651fc9969d42a73ae5666982171782014e11 100644 --- a/src/components/Home.vue +++ b/src/components/Home.vue @@ -1,25 +1,32 @@ <template> - <div> - <div class="row"> - <div class="sidebar col-md-2"> - <div style="vertical-align: center" class="col-md-12"> - <p><a href="">Lehrerübersicht Archiv</a></p> - <p><a href="">Lehrerübersicht</a></p> - <p><a href="">Kursübersicht</a></p> - <p><a href="">Kalender</a></p> - <p><a href="">Vorlagen</a></p> - </div> - </div> - <div class="content col-md-10"> - - </div> - </div> + <div id="app"> + <div class="container"> + <router-view /> + </div> </div> </template> <script> + export default { - name: "Home" + name: "Home", + data() { + return { } + }, + + created() { + this.$route.push("/lehreruebersicht"); + }, + + methods:{ + + logOut: function() { + this.$store.dispatch('auth/logout'); + this.$router.push('/login'); + } + + + } } </script> diff --git a/src/components/LogIn.vue b/src/components/LogIn.vue index 6373792e6322511b19506d8d528656dfcc190148..744d4c2948945ac6610704e83b4b1674c2f0030e 100644 --- a/src/components/LogIn.vue +++ b/src/components/LogIn.vue @@ -22,7 +22,7 @@ <h1 class="formTitle" style="margin-top: 30px">E-Mail-Adresse</h1> <div class="input_container"> <img src="../assets/ic_mail.svg" class="input_img"> - <input v-model="username" type="text" class="form-control inputField" placeholder="Benutzername" aria-label="username"> + <input v-model="user.username" type="text" class="form-control inputField" placeholder="Benutzername" aria-label="username"> </div> </div> </div> @@ -31,14 +31,14 @@ <h1 class="formTitle" style="margin-top: 10px">Passwort</h1> <div class="input_container"> <img src="../assets/ic_password.svg" class="input_img"> - <input v-model="password" :type="passwordFieldType" class="form-control inputField" placeholder="Passwort" aria-label="password"> + <input v-model="user.password" :type="passwordFieldType" class="form-control inputField" placeholder="Passwort" aria-label="password"> <img src="../assets/ic_password_toggle.svg" :class="passwordToggleStyle" @click="changeVisibility"> </div> </div> </div> <div class="form-row"> <div class="col-md-11 mb-3"> - <button class="btn btn-primary btn-lg btn-block" style="margin-top: 20px; border-radius: 10px" @click="validate" type="button">Anmelden</button> + <button class="btn btn-primary btn-lg btn-block" style="margin-top: 20px; border-radius: 10px" @click="login" type="button">Anmelden</button> </div> </div> <div class="row"> @@ -58,12 +58,15 @@ </template> <script> -import axios from "axios"; +//import axios from "axios"; +import User from "@/models/user"; export default { name: "Login.vue", + data() { return { + user: new User('', '',''), username: "", //eslint-disable-next-line reg: /^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$/, @@ -71,6 +74,22 @@ export default { passwordFieldType: 'password', passwordToggleStyle: "password_toggle_img", + loading: false, + message: '' + + } + }, + + computed: { + loggedIn() { + // Falls der User schon angemeldet ist, direkte weiterleitung + return this.$store.state.auth.status.loggedIn; + } + }, + + created() { + if (this.loggedIn) { + this.$router.push('/home'); } }, @@ -91,22 +110,27 @@ export default { }, login() { - axios({ - method:'POST', - url: 'http://localhost:9192/authenticate', - headers: { - 'Access-Control-Allow-Origin': '*', - 'Content-Type': 'application/json', - }, - data: { - userName: this.username, - password: this.password + this.$validator.validateAll().then(isValid => { + if (!isValid) { + this.loading = false; + return; + } + + if (this.user.username && this.user.password) { + this.$store.dispatch('auth/login', this.user).then( + () => { + this.$router.push('/home'); + }, + error => { + this.loading = false; + this.message = + (error.response && error.response.data) || + error.message || + error.toString(); + } + ); } - }).then(function(response){ - console.log("response: "+response) - }).catch(error=>{ - console.log("error: "+error) - }) + }); }, changeVisibility() { diff --git a/src/components/SignIn.vue b/src/components/SignIn.vue index 442d1254cc25bb1cf778632620b766bb85a73ef2..0af18e86001a8a953468701b0624df30bbbe57c6 100644 --- a/src/components/SignIn.vue +++ b/src/components/SignIn.vue @@ -1,119 +1,184 @@ <template> - <div class="container-fluid"> - <div class="row"> - <div class="login-container col-md-4"> - <div class="row header"> - <div class="col-md-12"> - <img id="fu-logo" src="../assets/fub-logo.png" alt="Freie Universität Berlin Logo"> - </div> - </div> - <div class="row header"> - <div class="col-md-12"> - <h1>Willkommen !</h1> - <p>Bitte melden Sie sich an.</p> - </div> - </div> - <form class="login"> + <div> + <div class="row col-md-12"> + <div id="content" class="content col-md-12"> + <h2>Signup Page</h2> + <form @submit="register2" class="col-md-10" style="margin-bottom: 20px"> <div class="form-row"> - <div class="col-md-12 mb-3"> - <div class="input-group"> - <input v-model="firstname" type="text" class="form-control" placeholder="Vorname" aria-label="firstname" > + <div class="col-md-11 mb-3"> + <h1 class="formTitle" style="margin-top: 30px">Name</h1> + <div class="input_container"> + <img src="../assets/ic_mail.svg" class="input_img"> + <input v-model="user.name" type="text" class="form-control inputField" placeholder="Name" aria-label="username"> </div> </div> </div> <div class="form-row"> - <div class="col-md-12 mb-3"> - <div class="input-group"> - <input v-model="lastname" type="text" class="form-control" placeholder="Nachname" aria-label="nachname" > + <div class="col-md-11 mb-3"> + <h1 class="formTitle" style="margin-top: 30px">Benutzername</h1> + <div class="input_container"> + <img src="../assets/ic_mail.svg" class="input_img"> + <input v-model="user.username" type="text" class="form-control inputField" placeholder="Benutzername" aria-label="username"> </div> </div> </div> <div class="form-row"> - <div class="col-md-12 mb-3"> - <div class="input-group"> - <input v-model="email" type="text" class="form-control" placeholder="E-Mail-Adresse" aria-label="email" > + <div class="col-md-11 mb-3"> + <div id="wronginputwarning" class="wronginput_container" style="visibility: hidden;"> + <img src="../assets/error.svg" class="inputwrong_img"> + <label id="wronginputlabel" style="color: #d75a4a;">E-Mail-Adresse oder Passwort ungültig.</label> + </div> + <h1 class="formTitle" style="margin-top: 10px">E-Mail-Adresse</h1> + <div class="input_container"> + <img src="../assets/ic_mail.svg" class="input_img"> + <input v-model="user.email" type="text" class="form-control inputField" placeholder="E-Mail-Adresse" aria-label="username"> </div> </div> </div> <div class="form-row"> - <div class="col-md-12 mb-3"> - <div class="input-group"> - <input v-model="password" type="text" class="form-control" placeholder="Passwort" aria-label="password"> + <div class="col-md-11 mb-3"> + <h1 class="formTitle" style="margin-top: 10px">Passwort</h1> + <div class="input_container"> + <img src="../assets/ic_password.svg" class="input_img"> + <input v-model="user.password" :type="passwordFieldType" class="form-control inputField" placeholder="Passwort" aria-label="password"> </div> </div> </div> <div class="form-row"> - <div class="col-md-12 mb-3"> - <button class="btn btn-primary btn-lg btn-block" @click="verifycorrectness" type="submit">Registrieren</button> - </div> - </div> - <div class="row"> - <div class="col-md-12 mb-3"> + <div class="col-md-11 mb-3"> + <button class="btn btn-primary btn-lg btn-block" style="margin-top: 20px; border-radius: 10px" type="submit">Registrieren</button> </div> </div> </form> </div> - <div class="container-right col-md-8"> - </div> </div> </div> </template> <script> +import User from "@/models/user"; + export default { name: "SignIn.vue", - data() { + data(){ return { - email: "", - //eslint-disable-next-line - reg: /^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$/, - showPass: false, - password: "" + user: new User('','', '', '') } }, - methods:{ - verifycorrectness(){ - if (this.reg.test(this.email)) { - this.submitNewUser() - } else { - alert("Geben Sie eine gültige E-Mail-Adresse ein!") - } - }, - submitNewUser() { - alert('Add to Database') + + methods: { + register2: function () { + + this.$validator.validate().then(isValid => { + if (isValid) { + this.$store.dispatch('auth/register', this.user).then( + data => { + this.message = data.message; + this.successful = true; + }, + error => { + this.message = + (error.response && error.response.data) || + error.message || + error.toString(); + this.successful = false; + } + ); + } + }); + } } } </script> <style scoped> +div.content { + background-color: whitesmoke; + position: fixed; + padding: 1px 16px; + height: 1000px; +} -</style> +.imgContainer{ + max-height: 100%; + max-width: 100%; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} -<!-- Add "scoped" attribute to limit CSS to this component only --> -<style scoped> +.title { + font-size: 44px; + font-weight: bold; + color: #252529; +} + +.subTitle { + font-size: 24px; + font-weight: bold; + color: #252529; +} -html, body{ - overflow: hidden; +.formTitle { + font-size: 14px; + font-weight: 500; + color: #6B6C6F; } -#fu-logo{ - width: 50%; +.inputField { + height: 44px; + margin-top: 10px; + padding-left: 70px; + padding-right: 70px; + border-color: #DFE2E6; + border-width: 2px; + border-radius: 10px; } -.header{ - margin-top: 40px ; + +.input_container { + position:relative; } -.login{ - margin-top: 20px; + +.input_img { + position:absolute; + filter: invert(97%) sepia(3%) saturate(365%) hue-rotate(181deg) brightness(95%) contrast(89%); + top: 10px; + left:20px; + width:24px; + height:24px; } -.login-container{ - border: solid 1px white; - margin-bottom: 350px; +.inputwrong_img { + position:absolute; + filter: invert(97%) sepia(3%) saturate(365%) hue-rotate(181deg) brightness(95%) contrast(89%); + left:20px; + width:24px; + height:24px; } -.container-right { - background: lightgray; +.wronginput_container { + margin-top: 25px; + padding-left: 50px; + padding-right: 70px; + border-color: #DFE2E6; + border-width: 2px; + border-radius: 10px; +} + +.password_toggle_img { + position:absolute; + filter: invert(97%) sepia(3%) saturate(365%) hue-rotate(181deg) brightness(95%) contrast(89%); + top: 10px; + right:20px; + width:24px; + height:24px; +} +.password_toggle_img_active { + filter: invert(10%) sepia(6%) saturate(905%) hue-rotate(201deg) brightness(99%) contrast(88%); } -</style> +</style> \ No newline at end of file diff --git a/src/components/main/Lehreruebersicht.vue b/src/components/main/Lehreruebersicht.vue index 5986c174d244d8fb9841661f185be9f1641be1a5..da1b2300543d527052d54360ba7a97566f35a72f 100644 --- a/src/components/main/Lehreruebersicht.vue +++ b/src/components/main/Lehreruebersicht.vue @@ -1,5 +1,5 @@ <template> -$END$ + <div style="height:100vh; background: #2c3e50"></div> </template> <script> diff --git a/src/main.js b/src/main.js index dba76a16e13ec285ab92678b44369e8c886f5102..886ba9ac392898ba2a8f6fe1aaec742f40de95c7 100644 --- a/src/main.js +++ b/src/main.js @@ -1,29 +1,28 @@ -import BootstrapVue from "bootstrap-vue" -import "bootstrap/dist/css/bootstrap.min.css" -import "bootstrap-vue/dist/bootstrap-vue.css" import Vue from 'vue' import App from './App.vue' -import store from './store'; -import Axios from 'axios'; -import VueRouter from 'vue-router' -import routes from './router' +import router from './router' +import store from './store/index'; -Vue.use(BootstrapVue) -Vue.use(VueRouter) +import BootstrapVue from "bootstrap-vue" +import "bootstrap/dist/css/bootstrap.min.css" +import "bootstrap-vue/dist/bootstrap-vue.css" + +import VeeValidate from 'vee-validate'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; +import { faHome, faUser, faUserPlus, faSignInAlt, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; -const router = new VueRouter({ - mode: 'history', // add this - routes -}) +library.add(faHome, faUser, faUserPlus, faSignInAlt, faSignOutAlt); Vue.config.productionTip = false; -// set auth header -Axios.defaults.headers.common['Authorization'] = `Bearer ${store.state.token}`; -new Vue({ - render: h => h(App), +Vue.use(BootstrapVue) +Vue.use(VeeValidate); +Vue.component('font-awesome-icon', FontAwesomeIcon); +new Vue({ router, - store + store, + render: h => h(App) }).$mount('#app'); diff --git a/src/router.js b/src/router.js index 7125c50a0a68833c1013e8300a3d95a599f3ed17..87b94c46234fb88ce73beb844cfced966b5b6afe 100644 --- a/src/router.js +++ b/src/router.js @@ -1,32 +1,86 @@ +import Vue from 'vue' +import Router from 'vue-router' + import Home from "./components/Home"; -import LogIn from "./components/LogIn"; -import SignIn from "./components/SignIn"; - -const routes = [ - { - path: '/login', - name: 'login', - component: LogIn, - meta: { - guest: true - } - }, - { - path: '/home', - name: 'home', - component: Home, - meta: { - requiresAuth: true - } - }, - { - path: '/singin', - name: 'singin', - component: SignIn, - meta: { - requiresAuth: true, - is_admin: true +import Login from "./components/LogIn"; +import Register from "./components/SignIn"; + +import Lehreruebersicht from "./components/main/Lehreruebersicht"; + +Vue.use(Router) + +const router = new Router({ + mode: 'history', + base: process.env.BASE_URL, + routes: [ + + // LOGIN / REGISTER + { + path: '/login', + name: 'Login von Natlab', + component: Login + }, + { + path: '/register', + name: 'Register von Natlab', + component: Register + }, + + // MAIN CONTENT + { + path: '/', + name: 'home', + component: Home + }, + { + path: '/home', + component: Home + }, + { + path: '/lehreruebersicht', + name: 'Lehrerübersicht', + component: Lehreruebersicht + }, + + { + path: '/profile', + name: 'profile', + // lazy-loaded + component: () => import('./views/Profile.vue') + }, + { + path: '/admin', + name: 'admin', + // lazy-loaded + component: () => import('./views/BoardAdmin.vue') + }, + { + path: '/mod', + name: 'moderator', + // lazy-loaded + component: () => import('./views/BoardModerator.vue') + }, + { + path: '/user', + name: 'user', + // lazy-loaded + component: () => import('./views/BoardUser.vue') } + ] +}) + +router.beforeEach((to, from, next) => { + const publicPages = ['/login', '/register', '/home']; + const authRequired = !publicPages.includes(to.path); + const loggedIn = localStorage.getItem('user'); + + // trying to access a restricted page + not logged in + // redirect to login page + if (authRequired && !loggedIn) { + next('/login'); + } else { + next(); } -] -export default routes \ No newline at end of file +}); + +export default router \ No newline at end of file diff --git a/src/services/auth-header.js b/src/services/auth-header.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8641414928ebcf315ad9aefbfff2c0d525cb0c98 100644 --- a/src/services/auth-header.js +++ b/src/services/auth-header.js @@ -0,0 +1,9 @@ +export default function authHeader() { + let user = JSON.parse(localStorage.getItem('user')); + + if (user && user.accessToken) { + return { Authorization: 'Bearer ' + user.accessToken }; + } else { + return {}; + } +} \ No newline at end of file diff --git a/src/services/auth.service.js b/src/services/auth.service.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cba6f5b19292036e1ecdf7ead0f2ac02adbffdc8 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -0,0 +1,37 @@ +import axios from 'axios'; +import authHeader from "@/services/auth-header"; + +const API_URL = 'http://localhost:9192/'; + +class AuthService { + + login(user) { + return axios + .post(API_URL + 'authenticate', { + userName: user.username, + password: user.password + }) + .then(response => { + + if (response.data.idToken) { + localStorage.setItem('user', JSON.stringify(response.data)); + } + + return response.data; + }); + } + + logout() { + localStorage.removeItem('user'); + } + + register(user) { + return axios.post(API_URL + 'register', { + username: user.username, + email: user.email, + password: user.password + },{ headers: authHeader() }); + } +} + +export default new AuthService(); diff --git a/src/services/user.service.js b/src/services/user.service.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3c4a17dcb8d1edc4b18b84aa2aa514bb3a548a1f 100644 --- a/src/services/user.service.js +++ b/src/services/user.service.js @@ -0,0 +1,25 @@ +import axios from 'axios'; +import authHeader from './auth-header'; + +const API_URL = 'http://localhost:9192/'; + +class UserService { + + getPublicContent() { + return axios.get(API_URL + 'hello'); + } + + getUserBoard() { + return axios.get(API_URL + 'user', { headers: authHeader() }); + } + + getModeratorBoard() { + return axios.get(API_URL + 'mod', { headers: authHeader() }); + } + + getAdminBoard() { + return "Hello"; //axios.get(API_URL + 'admin', { headers: authHeader() }); + } +} + +export default new UserService(); \ No newline at end of file diff --git a/src/store/auth.module.js b/src/store/auth.module.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6ba7445ceb3db943c5ccf8c0ddbdb8ff81e090bd 100644 --- a/src/store/auth.module.js +++ b/src/store/auth.module.js @@ -0,0 +1,66 @@ +import AuthService from '../services/auth.service'; +import User from "@/models/user"; + +const user = JSON.parse(localStorage.getItem('user')); +const initialState = user + ? { status: { loggedIn: true }, user } + : { status: { loggedIn: false }, user: new User("", "", "") }; + +export const auth = { + namespaced: true, + state: initialState, + actions: { + + login({ commit }, user) { + return AuthService.login(user).then( + user => { + commit('loginSuccess', user); + return Promise.resolve(user); + }, + error => { + commit('loginFailure'); + return Promise.reject(error); + } + ); + }, + + logout({ commit }) { + AuthService.logout(); + commit('logout'); + }, + + register({ commit }, user) { + return AuthService.register(user).then( + response => { + commit('registerSuccess'); + return Promise.resolve(response.data); + }, + error => { + commit('registerFailure'); + return Promise.reject(error); + } + ); + } + }, + + mutations: { + loginSuccess(state, user) { + state.status.loggedIn = true; + state.user = user; + }, + loginFailure(state) { + state.status.loggedIn = false; + state.user = null; + }, + logout(state) { + state.status.loggedIn = false; + state.user = null; + }, + registerSuccess(state) { + state.status.loggedIn = false; + }, + registerFailure(state) { + state.status.loggedIn = false; + } + } +}; \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..adbb163c9f3a9bb1bbe78b75865aae324564d89e 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -0,0 +1,12 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; + +import { auth } from './auth.module'; + +Vue.use(Vuex); + +export default new Vuex.Store({ + modules: { + auth + } +}); \ No newline at end of file diff --git a/src/views/BoardAdmin.vue b/src/views/BoardAdmin.vue index 4d7b92d915c6d428646d0dbd19e49d3ec73a3e9e..a97469a2b27802225c5201ef72504cceb74db120 100644 --- a/src/views/BoardAdmin.vue +++ b/src/views/BoardAdmin.vue @@ -1,10 +1,10 @@ <template> -$END$ + <div></div> </template> <script> export default { -name: "BoardAdmin" + name: "BoardAdmin" } </script> diff --git a/src/views/BoardModerator.vue b/src/views/BoardModerator.vue index ab55c057ebabb5947693a2c9e297068268ad1463..885c1e702405ab03eed3b5fd1eef0a1e408ee73a 100644 --- a/src/views/BoardModerator.vue +++ b/src/views/BoardModerator.vue @@ -1,10 +1,11 @@ <template> -$END$ + + <div></div> </template> <script> export default { -name: "BoardModerator" + name: "BoardModerator" } </script> diff --git a/src/views/BoardUser.vue b/src/views/BoardUser.vue index 1513417ac021257282b6737ca39e12bd16cedc12..af08d1be19118145426601ece99f309a1b3027cc 100644 --- a/src/views/BoardUser.vue +++ b/src/views/BoardUser.vue @@ -1,11 +1,35 @@ <template> -$END$ + <div class="container"> + <header class="jumbotron"> + <h3>{{content}}</h3> + </header> + </div> </template> <script> +import UserService from '../services/user.service'; + export default { -name: "BoeardUser" -} + name: 'User', + data() { + return { + content: '' + }; + }, + mounted() { + UserService.getUserBoard().then( + response => { + this.content = response.data; + }, + error => { + this.content = + (error.response && error.response.data) || + error.message || + error.toString(); + } + ); + } +}; </script> <style scoped> diff --git a/src/views/Profile.vue b/src/views/Profile.vue index 1572944ab439b5a6c42532ecd557c2e9cea66d28..5cd30511a9672f5a169b2db31a24f9b595d0e963 100644 --- a/src/views/Profile.vue +++ b/src/views/Profile.vue @@ -1,11 +1,46 @@ <template> -$END$ + <div class="container"> + <header class="jumbotron"> + <h3> + <!--strong>{{currentUser.username}}</strong--> Profile + <strong>username</strong> Profile + </h3> + </header> + <p> + <strong>Token:</strong> + {{currentUser.idToken.substring(0, 20)}} ... {{currentUser.idToken.substr(currentUser.idToken.length - 20)}} + </p> + <p> + <strong>Id:</strong> + <!--{{currentUser.id}}--> + userId + </p> + <p> + <strong>Email:</strong> + <!--{{currentUser.email}}--> + userEmail + </p> + <strong>Authorities:</strong> + <ul> + <!--li v-for="(role,index) in currentUser.roles" :key="index">{{role}}</li--> + </ul> + </div> </template> <script> export default { -name: "Profile" -} + name: 'Profile', + computed: { + currentUser() { + return this.$store.state.auth.user; + } + }, + mounted() { + if (!this.currentUser) { + this.$router.push('/login'); + } + } +}; </script> <style scoped>