mirror of
https://github.com/janishutz/libreevent.git
synced 2026-09-22 13:15:25 +02:00
restruct + 2fa + auth
This commit is contained in:
1 parent
d0647ba1bb
commit
865141d945
26 files changed
+279
-127
No files matched your search
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div id="notifications" @click="handleNotifications();">
|
||||
<div class="message-box" :class="location">
|
||||
<div class="message-box" :class="[ location, size ]">
|
||||
<div class="message-container" :class="messageType">
|
||||
<span class="material-symbols-outlined types hide" v-if="messageType == 'hide'">question_mark</span>
|
||||
<span class="material-symbols-outlined types" v-else-if="messageType == 'ok'" style="background-color: green;">done</span>
|
||||
@@ -21,7 +21,12 @@
|
||||
location: {
|
||||
type: String,
|
||||
'default': 'topleft',
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
'default': 'default',
|
||||
}
|
||||
// Size options: small, default (default option), big, bigger, huge
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -119,9 +124,32 @@
|
||||
position: fixed;
|
||||
z-index: 10;
|
||||
color: white;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.default {
|
||||
height: 10vh;
|
||||
width: 15vw;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.small {
|
||||
height: 7vh;
|
||||
width: 11vw;
|
||||
}
|
||||
|
||||
.big {
|
||||
height: 12vh;
|
||||
width: 17vw;
|
||||
}
|
||||
|
||||
.bigger {
|
||||
height: 15vh;
|
||||
width: 20vw;
|
||||
}
|
||||
|
||||
.huge {
|
||||
height: 20vh;
|
||||
width: 25vw;
|
||||
}
|
||||
|
||||
.topleft {
|
||||
|
||||
@@ -55,6 +55,10 @@ router.beforeEach( ( to, from ) => {
|
||||
return { name: 'purchase' };
|
||||
} else if ( to.name.substring( 0, 5 ) === 'setup' && !backendStore.getVisitedSetupPages[ to.name.substring( 5 ).toLowerCase() ] && to.name.substring( 5 ).toLowerCase() !== 'start' && to.name.substring( 5 ).toLowerCase() !== 'root' ) {
|
||||
return { name: 'setupStart' };
|
||||
} else if ( to.name === '2fa' && !userStore.getUserTwoFACompliant ) {
|
||||
return { name: 'login' };
|
||||
} else if ( to.name === 'Admin2fa' && !userStore.getAdminTwoFACompliant ) {
|
||||
return { name: 'adminLogin' };
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export default [
|
||||
{
|
||||
path: '/tickets',
|
||||
name: 'tickets',
|
||||
component: () => import( '../views/OrderView.vue' ),
|
||||
component: () => import( '../views/purchasing/OrderView.vue' ),
|
||||
meta: {
|
||||
title: 'Order ticket - libreevent'
|
||||
}
|
||||
@@ -35,7 +35,7 @@ export default [
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import( '../views/LoginView.vue' ),
|
||||
component: () => import( '../views/user/LoginView.vue' ),
|
||||
meta: {
|
||||
title: 'Login - libreevent'
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export default [
|
||||
{
|
||||
path: '/admin/login',
|
||||
name: 'adminLogin',
|
||||
component: () => import( '../views/AdminLoginView.vue' ),
|
||||
component: () => import( '../views/admin/AdminLoginView.vue' ),
|
||||
meta: {
|
||||
title: 'Login :: Admin - libreevent'
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export default [
|
||||
{
|
||||
path: '/signup',
|
||||
name: 'signup',
|
||||
component: () => import( '../views/SignupView.vue' ),
|
||||
component: () => import( '../views/user/SignupView.vue' ),
|
||||
meta: {
|
||||
title: 'Signup - libreevent'
|
||||
}
|
||||
@@ -59,15 +59,23 @@ export default [
|
||||
{
|
||||
path: '/account',
|
||||
name: 'account',
|
||||
component: () => import( '../views/AccountView.vue' ),
|
||||
component: () => import( '../views/user/AccountView.vue' ),
|
||||
meta: {
|
||||
title: 'Account - libreevent'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/twoFactors',
|
||||
name: '2fa',
|
||||
component: () => import( '../views/user/TwoFA.vue' ),
|
||||
meta: {
|
||||
title: 'Two Factor Authentication - libreevent'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/tickets/details',
|
||||
name: 'ticketDetails',
|
||||
component: () => import( '../views/TicketsDetailsView.vue' ),
|
||||
component: () => import( '../views/purchasing/TicketsDetailsView.vue' ),
|
||||
meta: {
|
||||
title: 'Details - libreevent',
|
||||
transition: 'scale'
|
||||
@@ -76,7 +84,7 @@ export default [
|
||||
{
|
||||
path: '/tickets/order',
|
||||
name: 'ticketOrder',
|
||||
component: () => import( '../views/TicketsOrderingView.vue' ),
|
||||
component: () => import( '../views/purchasing/TicketsOrderingView.vue' ),
|
||||
meta: {
|
||||
title: 'Order ticket - libreevent',
|
||||
transition: 'scale'
|
||||
@@ -85,7 +93,7 @@ export default [
|
||||
{
|
||||
path: '/cart',
|
||||
name: 'cart',
|
||||
component: () => import( '../views/CartView.vue' ),
|
||||
component: () => import( '../views/purchasing/CartView.vue' ),
|
||||
meta: {
|
||||
title: 'Cart - libreevent',
|
||||
transition: 'scale'
|
||||
@@ -94,7 +102,7 @@ export default [
|
||||
{
|
||||
path: '/purchase',
|
||||
name: 'purchase',
|
||||
component: () => import( '@/views/PurchaseView.vue' ),
|
||||
component: () => import( '@/views/purchasing/PurchaseView.vue' ),
|
||||
meta: {
|
||||
title: 'Purchase - libreevent',
|
||||
transition: 'scale'
|
||||
@@ -103,21 +111,12 @@ export default [
|
||||
{
|
||||
path: '/pay',
|
||||
name: 'pay',
|
||||
component: () => import( '@/views/PaymentView.vue' ),
|
||||
component: () => import( '@/views/purchasing/PaymentView.vue' ),
|
||||
meta: {
|
||||
title: 'Pay - libreevent',
|
||||
transition: 'scale',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import( '@/views/404.vue' ),
|
||||
meta: {
|
||||
title: '404 - Page not found :: libreevent',
|
||||
transition: 'scale',
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/admin/seatplan',
|
||||
name: 'adminSeatplanEditor',
|
||||
@@ -136,4 +135,13 @@ export default [
|
||||
adminAuthRequired: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import( '@/views/404.vue' ),
|
||||
meta: {
|
||||
title: '404 - Page not found :: libreevent',
|
||||
transition: 'scale',
|
||||
}
|
||||
},
|
||||
]
|
||||
@@ -10,7 +10,7 @@
|
||||
export default {
|
||||
path: '/setup',
|
||||
name: 'setup',
|
||||
component: () => import( '../views/SetupView.vue' ),
|
||||
component: () => import( '../views/setup/SetupView.vue' ),
|
||||
meta: {
|
||||
title: 'Login :: Admin - libreevent',
|
||||
setupAuthRequired: true,
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useUserStore = defineStore ( 'user', {
|
||||
state: () => ( { 'isUserAuth': true, 'isAdminAuth': true, 'userData': {} } ),
|
||||
state: () => ( { 'isUserAuth': false, 'isAdminAuth': false, 'userData': {}, 'isTwoFACompliantUser': false, 'isTwoFACompliantAdmin': false } ),
|
||||
getters: {
|
||||
getUserAuthenticated: ( state ) => state.isUserAuth,
|
||||
getAdminAuthenticated: ( state ) => state.isAdminAuth,
|
||||
getUserTwoFACompliant: ( state ) => state.isTwoFACompliantUser,
|
||||
getAdminTwoFACompliant: ( state ) => state.isTwoFACompliantAdmin,
|
||||
},
|
||||
actions: {
|
||||
setUserAuth ( auth ) {
|
||||
@@ -21,6 +23,12 @@ export const useUserStore = defineStore ( 'user', {
|
||||
},
|
||||
setAdminAuth ( auth ) {
|
||||
this.isAdminAuth = auth;
|
||||
},
|
||||
setUser2fa ( auth ) {
|
||||
this.isTwoFACompliantUser = auth;
|
||||
},
|
||||
setAdmin2fa ( auth ) {
|
||||
this.isTwoFACompliantAdmin = auth;
|
||||
}
|
||||
}
|
||||
} );
|
||||
@@ -1,84 +0,0 @@
|
||||
<!--
|
||||
* libreevent - LoginView.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/14/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="login">
|
||||
<div class="login-app">
|
||||
<h1>Log in</h1>
|
||||
<form>
|
||||
<label for="mail">Email</label><br>
|
||||
<input type="email" v-model="formData[ 'mail' ]" name="mail" id="mail" required><br><br>
|
||||
<label for="password">Password</label><br>
|
||||
<input type="password" v-model="formData[ 'password' ]" name="password" id="password" required>
|
||||
</form>
|
||||
<button @click="login();" class="button">Log in</button>
|
||||
<router-link to="/signup" class="button">Sign up instead</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import { mapStores } from 'pinia';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores( useUserStore )
|
||||
},
|
||||
methods: {
|
||||
login () {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ? sessionStorage.getItem( 'redirect' ) : '/account' );
|
||||
sessionStorage.removeItem( 'redirect' );
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
/* TODO: Update colour to image */
|
||||
.login {
|
||||
background-color: green;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.login-app {
|
||||
background-color: var( --background-color );
|
||||
min-height: fit-content;
|
||||
min-height: fit-content;
|
||||
padding: 5% 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
margin-top: 2%;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: initial;
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,122 @@
|
||||
<!--
|
||||
* libreevent - LoginView.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/14/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="login">
|
||||
<div class="login-app">
|
||||
<h1>Log in</h1>
|
||||
<form>
|
||||
<label for="mail">Email</label><br>
|
||||
<input type="email" v-model="formData[ 'mail' ]" name="mail" id="mail" required><br><br>
|
||||
<label for="password">Password</label><br>
|
||||
<input type="password" v-model="formData[ 'password' ]" name="password" id="password" required>
|
||||
</form>
|
||||
<button @click="login();" class="button">Log in</button>
|
||||
<router-link to="/signup" class="button">Sign up instead</router-link>
|
||||
</div>
|
||||
<notifications ref="notification" location="topright" size="bigger"></notifications>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
import { mapStores } from 'pinia';
|
||||
import notifications from '@/components/notifications/notifications.vue';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
notifications,
|
||||
},
|
||||
computed: {
|
||||
...mapStores( useUserStore )
|
||||
},
|
||||
methods: {
|
||||
login () {
|
||||
if ( this.formData.mail ) {
|
||||
if ( this.formData.password ) {
|
||||
let fetchOptions = {
|
||||
method: 'post',
|
||||
body: JSON.stringify( this.formData ),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'charset': 'utf-8'
|
||||
}
|
||||
};
|
||||
fetch( localStorage.getItem( 'url' ) + '/user/login', fetchOptions ).then( res => {
|
||||
res.text().then( text => {
|
||||
console.log( text );
|
||||
if ( text === 'ok' ) {
|
||||
this.userStore.setUserAuth( true );
|
||||
this.$router.push( sessionStorage.getItem( 'redirect' ) ? sessionStorage.getItem( 'redirect' ) : '/account' );
|
||||
sessionStorage.removeItem( 'redirect' );
|
||||
} else if ( text === '2fa' ) {
|
||||
this.userStore.setUser2fa( true );
|
||||
this.$router.push( '/twoFactors' );
|
||||
} else {
|
||||
this.$refs.notification.createNotification( 'The credentials you provided do not match our records.', 5, 'error', 'normal' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
} else {
|
||||
this.$refs.notification.createNotification( 'A password is required to log in', 5, 'error', 'normal' );
|
||||
}
|
||||
} else {
|
||||
this.$refs.notification.createNotification( 'An email address is required to log in', 5, 'error', 'normal' );
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
/* TODO: Update colour to image */
|
||||
.login {
|
||||
background-color: green;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex: 0 1 auto;
|
||||
}
|
||||
|
||||
.login-app {
|
||||
background-color: var( --background-color );
|
||||
min-height: fit-content;
|
||||
min-height: fit-content;
|
||||
padding: 5% 20%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
margin-top: 2%;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#missing-email, #missing-password, #credentials-wrong {
|
||||
display: none;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
File renamed without changes.
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<div id="2fa">
|
||||
<h1>Two Factor Authentication</h1>
|
||||
<p>We have sent you an email containing a link for Authentication.</p>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user