This commit is contained in:
5
app/ayanova/package-lock.json
generated
5
app/ayanova/package-lock.json
generated
@@ -9729,6 +9729,11 @@
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"jwt-decode": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
|
||||
"integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk="
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.0.0-rc.1",
|
||||
"jwt-decode": "^2.2.0",
|
||||
"register-service-worker": "^1.0.0",
|
||||
"vue": "^2.5.17",
|
||||
"vue-router": "^3.0.1",
|
||||
@@ -84,4 +85,4 @@
|
||||
],
|
||||
"testURL": "http://localhost/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Vue from "vue";
|
||||
import Router from "vue-router";
|
||||
import Home from "./views/Home.vue";
|
||||
import { isLoggedIn, login, logout } from './utils/auth';
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
@@ -44,34 +45,34 @@ export default new Router({
|
||||
]
|
||||
});
|
||||
|
||||
// router.beforeEach((to, from, next) => {
|
||||
// if(to.matched.some(record => record.meta.requiresAuth)) {
|
||||
// if (localStorage.getItem('jwt') == null) {
|
||||
// next({
|
||||
// path: '/login',
|
||||
// params: { nextUrl: to.fullPath }
|
||||
// })
|
||||
// } else {
|
||||
// let user = JSON.parse(localStorage.getItem('user'))
|
||||
// if(to.matched.some(record => record.meta.is_admin)) {
|
||||
// if(user.is_admin == 1){
|
||||
// next()
|
||||
// }
|
||||
// else{
|
||||
// next({ name: 'userboard'})
|
||||
// }
|
||||
// }else {
|
||||
// next()
|
||||
// }
|
||||
// }
|
||||
// } else if(to.matched.some(record => record.meta.guest)) {
|
||||
// if(localStorage.getItem('jwt') == null){
|
||||
// next()
|
||||
// }
|
||||
// else{
|
||||
// next({ name: 'userboard'})
|
||||
// }
|
||||
// }else {
|
||||
// next()
|
||||
// }
|
||||
// })
|
||||
router.beforeEach((to, from, next) => {
|
||||
if(to.matched.some(record => record.meta.requiresAuth)) {
|
||||
if (localStorage.getItem('jwt') == null) {
|
||||
next({
|
||||
path: '/login',
|
||||
params: { nextUrl: to.fullPath }
|
||||
})
|
||||
} else {
|
||||
let user = JSON.parse(localStorage.getItem('user'))
|
||||
if(to.matched.some(record => record.meta.is_admin)) {
|
||||
if(user.is_admin == 1){
|
||||
next()
|
||||
}
|
||||
else{
|
||||
next({ name: 'userboard'})
|
||||
}
|
||||
}else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
} else if(to.matched.some(record => record.meta.guest)) {
|
||||
if(localStorage.getItem('jwt') == null){
|
||||
next()
|
||||
}
|
||||
else{
|
||||
next({ name: 'userboard'})
|
||||
}
|
||||
}else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,10 +6,10 @@ Vue.use(Vuex);
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
authenticated: false,
|
||||
mockAccount: {
|
||||
username: "manager",
|
||||
password: "letmein"
|
||||
}
|
||||
mockAccount: {
|
||||
username: "manager",
|
||||
password: "letmein"
|
||||
}
|
||||
},
|
||||
mutations: {},
|
||||
actions: {}
|
||||
|
||||
104
app/ayanova/src/utils/auth.js
Normal file
104
app/ayanova/src/utils/auth.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import decode from "jwt-decode";
|
||||
//import axios from 'axios';
|
||||
//import auth0 from 'auth0-js';
|
||||
//import Router from 'vue-router';
|
||||
//import Auth0Lock from 'auth0-lock';
|
||||
const ID_TOKEN_KEY = "id_token";
|
||||
const ACCESS_TOKEN_KEY = "access_token";
|
||||
|
||||
// const CLIENT_ID = '{AUTH0_CLIENT_ID}';
|
||||
// const CLIENT_DOMAIN = '{AUTH0_DOMAIN}';
|
||||
// const REDIRECT = 'YOUR_CALLBACK_URL';
|
||||
// const SCOPE = '{SCOPE}';
|
||||
// const AUDIENCE = 'AUDIENCE_ATTRIBUTE';
|
||||
|
||||
// var auth = new auth0.WebAuth({
|
||||
// clientID: CLIENT_ID,
|
||||
// domain: CLIENT_DOMAIN
|
||||
// });
|
||||
|
||||
export function login() {
|
||||
// auth.authorize({
|
||||
// responseType: 'token id_token',
|
||||
// redirectUri: REDIRECT,
|
||||
// audience: AUDIENCE,
|
||||
// scope: SCOPE
|
||||
// });
|
||||
}
|
||||
|
||||
// var router = new Router({
|
||||
// mode: 'history',
|
||||
// });
|
||||
|
||||
export function logout() {
|
||||
clearIdToken();
|
||||
clearAccessToken();
|
||||
//router.go('/');
|
||||
}
|
||||
|
||||
// export function requireAuth(to, from, next) {
|
||||
// if (!isLoggedIn()) {
|
||||
// next({
|
||||
// path: '/',
|
||||
// query: { redirect: to.fullPath }
|
||||
// });
|
||||
// } else {
|
||||
// next();
|
||||
// }
|
||||
// }
|
||||
|
||||
export function getIdToken() {
|
||||
return localStorage.getItem(ID_TOKEN_KEY);
|
||||
}
|
||||
|
||||
export function getAccessToken() {
|
||||
return localStorage.getItem(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
|
||||
function clearIdToken() {
|
||||
localStorage.removeItem(ID_TOKEN_KEY);
|
||||
}
|
||||
|
||||
function clearAccessToken() {
|
||||
localStorage.removeItem(ACCESS_TOKEN_KEY);
|
||||
}
|
||||
|
||||
// Helper function that will allow us to extract the access_token and id_token
|
||||
function getParameterByName(name) {
|
||||
let match = RegExp("[#&]" + name + "=([^&]*)").exec(window.location.hash);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
// Get and store access_token in local storage
|
||||
export function setAccessToken() {
|
||||
let accessToken = getParameterByName("access_token");
|
||||
localStorage.setItem(ACCESS_TOKEN_KEY, accessToken);
|
||||
}
|
||||
|
||||
// Get and store id_token in local storage
|
||||
export function setIdToken() {
|
||||
let idToken = getParameterByName("id_token");
|
||||
localStorage.setItem(ID_TOKEN_KEY, idToken);
|
||||
}
|
||||
|
||||
export function isLoggedIn() {
|
||||
const idToken = getIdToken();
|
||||
return !!idToken && !isTokenExpired(idToken);
|
||||
}
|
||||
|
||||
function getTokenExpirationDate(encodedToken) {
|
||||
const token = decode(encodedToken);
|
||||
if (!token.exp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const date = new Date(0);
|
||||
date.setUTCSeconds(token.exp);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
function isTokenExpired(token) {
|
||||
const expirationDate = getTokenExpirationDate(token);
|
||||
return expirationDate < new Date();
|
||||
}
|
||||
@@ -1,47 +1,50 @@
|
||||
<template>
|
||||
<div id="login">
|
||||
<h1>Login</h1>
|
||||
<input type="text" name="username" v-model="input.username" placeholder="Username" />
|
||||
<input type="password" name="password" v-model="input.password" placeholder="Password" />
|
||||
<input type="text" name="username" v-model="input.username" placeholder="Username">
|
||||
<input type="password" name="password" v-model="input.password" placeholder="Password">
|
||||
<button type="button" v-on:click="login()">Login</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Login',
|
||||
data() {
|
||||
return {
|
||||
input: {
|
||||
username: "",
|
||||
password: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login() {
|
||||
if(this.input.username != "" && this.input.password != "") {
|
||||
if(this.input.username == this.$store.state.mockAccount.username && this.input.password == this.$store.state.mockAccount.password) {
|
||||
this.$emit("authenticated", true);
|
||||
this.$router.replace({ name: "secure" });
|
||||
} else {
|
||||
console.log("The username and / or password is incorrect");
|
||||
}
|
||||
} else {
|
||||
console.log("A username and password must be present");
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: "Login",
|
||||
data() {
|
||||
return {
|
||||
input: {
|
||||
username: "",
|
||||
password: ""
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
login() {
|
||||
if (this.input.username != "" && this.input.password != "") {
|
||||
if (
|
||||
this.input.username == this.$store.state.mockAccount.username &&
|
||||
this.input.password == this.$store.state.mockAccount.password
|
||||
) {
|
||||
this.$emit("authenticated", true);
|
||||
this.$router.replace({ name: "secure" });
|
||||
} else {
|
||||
alert("The username and / or password is incorrect");
|
||||
}
|
||||
} else {
|
||||
alert("A username and password must be present");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#login {
|
||||
width: 500px;
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #FFFFFF;
|
||||
margin: auto;
|
||||
margin-top: 200px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
#login {
|
||||
width: 500px;
|
||||
border: 1px solid #cccccc;
|
||||
background-color: #ffffff;
|
||||
margin: auto;
|
||||
margin-top: 200px;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,6 +65,14 @@ WEEK OF 2018-11-05 - RAVEN shell start work. YAY!
|
||||
- Reporting
|
||||
- Notifications from the server
|
||||
- File upload / download
|
||||
- Offline abilities?
|
||||
- Need a good think about this, time to market is of utmost importance but it would not hurt to see what can be done now or defferred to vNext
|
||||
- v7 is technically an always online app so there's that.
|
||||
- Would be nice to maybe be able to do some limited stuff offline
|
||||
- scope out a scenario or leave for vNext?
|
||||
- Fill out a workorder that is already up on the phone?
|
||||
- Parts can't be cached locally, there could be thousands, but maybe labour only is supported?
|
||||
- Maybe parts can be entered as text when offline for later lookup?
|
||||
- NOTE: many users want to see some progress on v8 so it's important that the initial shell have some "flash" to it
|
||||
- Nice transitions
|
||||
- Some sample charts
|
||||
|
||||
@@ -71,6 +71,23 @@ and VUEX allows that easily, plus it's fairly straightforward to use.
|
||||
Here is an example of how to structure a non trivial application with VUEX broken into modules:
|
||||
https://vuex.vuejs.org/guide/structure.html
|
||||
|
||||
VUEX STATE PERSISTENCE = VUEX-PERSISTEDSTATE
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
- https://github.com/robinvdvleuten/vuex-persistedstate
|
||||
- Some stuff should probably be persisted like auth, maybe other stuff?
|
||||
- Is this app an online only app?
|
||||
- Store enough stuff to keep working locally?
|
||||
- Fill out a workorder offline?
|
||||
- Create a new one offline?
|
||||
- enter labour only, no parts or other lengthy lookup stuff??
|
||||
- If recreating AyaNova 7 essentially, then that app is always online as well so maybe don't even consider offline work?
|
||||
|
||||
|
||||
LOCALSTORAGE = STORE.JS
|
||||
=-=-=-=-=-=-=-=-=-=-
|
||||
- Very widely used and I don't necessarily need a VUE specific one, this is the one used for pecklist and rockfish
|
||||
- https://github.com/marcuswestin/store.js/
|
||||
|
||||
SERVICEWORKER = WORKBOX
|
||||
=-=-=-=-=-=-=-=-=-=-=-=
|
||||
For offsite PWA use, works well and is simple to implement
|
||||
|
||||
Reference in New Issue
Block a user