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"
|
"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": {
|
"killable": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.0.0-rc.1",
|
"@babel/polyfill": "^7.0.0-rc.1",
|
||||||
|
"jwt-decode": "^2.2.0",
|
||||||
"register-service-worker": "^1.0.0",
|
"register-service-worker": "^1.0.0",
|
||||||
"vue": "^2.5.17",
|
"vue": "^2.5.17",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Router from "vue-router";
|
import Router from "vue-router";
|
||||||
import Home from "./views/Home.vue";
|
import Home from "./views/Home.vue";
|
||||||
|
import { isLoggedIn, login, logout } from './utils/auth';
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
@@ -44,34 +45,34 @@ export default new Router({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
// router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
// if(to.matched.some(record => record.meta.requiresAuth)) {
|
if(to.matched.some(record => record.meta.requiresAuth)) {
|
||||||
// if (localStorage.getItem('jwt') == null) {
|
if (localStorage.getItem('jwt') == null) {
|
||||||
// next({
|
next({
|
||||||
// path: '/login',
|
path: '/login',
|
||||||
// params: { nextUrl: to.fullPath }
|
params: { nextUrl: to.fullPath }
|
||||||
// })
|
})
|
||||||
// } else {
|
} else {
|
||||||
// let user = JSON.parse(localStorage.getItem('user'))
|
let user = JSON.parse(localStorage.getItem('user'))
|
||||||
// if(to.matched.some(record => record.meta.is_admin)) {
|
if(to.matched.some(record => record.meta.is_admin)) {
|
||||||
// if(user.is_admin == 1){
|
if(user.is_admin == 1){
|
||||||
// next()
|
next()
|
||||||
// }
|
}
|
||||||
// else{
|
else{
|
||||||
// next({ name: 'userboard'})
|
next({ name: 'userboard'})
|
||||||
// }
|
}
|
||||||
// }else {
|
}else {
|
||||||
// next()
|
next()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// } else if(to.matched.some(record => record.meta.guest)) {
|
} else if(to.matched.some(record => record.meta.guest)) {
|
||||||
// if(localStorage.getItem('jwt') == null){
|
if(localStorage.getItem('jwt') == null){
|
||||||
// next()
|
next()
|
||||||
// }
|
}
|
||||||
// else{
|
else{
|
||||||
// next({ name: 'userboard'})
|
next({ name: 'userboard'})
|
||||||
// }
|
}
|
||||||
// }else {
|
}else {
|
||||||
// next()
|
next()
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ Vue.use(Vuex);
|
|||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
state: {
|
state: {
|
||||||
authenticated: false,
|
authenticated: false,
|
||||||
mockAccount: {
|
mockAccount: {
|
||||||
username: "manager",
|
username: "manager",
|
||||||
password: "letmein"
|
password: "letmein"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
actions: {}
|
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>
|
<template>
|
||||||
<div id="login">
|
<div id="login">
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<input type="text" name="username" v-model="input.username" placeholder="Username" />
|
<input type="text" name="username" v-model="input.username" placeholder="Username">
|
||||||
<input type="password" name="password" v-model="input.password" placeholder="Password" />
|
<input type="password" name="password" v-model="input.password" placeholder="Password">
|
||||||
<button type="button" v-on:click="login()">Login</button>
|
<button type="button" v-on:click="login()">Login</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Login',
|
name: "Login",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
input: {
|
input: {
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: ""
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
login() {
|
login() {
|
||||||
if(this.input.username != "" && this.input.password != "") {
|
if (this.input.username != "" && this.input.password != "") {
|
||||||
if(this.input.username == this.$store.state.mockAccount.username && this.input.password == this.$store.state.mockAccount.password) {
|
if (
|
||||||
this.$emit("authenticated", true);
|
this.input.username == this.$store.state.mockAccount.username &&
|
||||||
this.$router.replace({ name: "secure" });
|
this.input.password == this.$store.state.mockAccount.password
|
||||||
} else {
|
) {
|
||||||
console.log("The username and / or password is incorrect");
|
this.$emit("authenticated", true);
|
||||||
}
|
this.$router.replace({ name: "secure" });
|
||||||
} else {
|
} else {
|
||||||
console.log("A username and password must be present");
|
alert("The username and / or password is incorrect");
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
alert("A username and password must be present");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#login {
|
#login {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
border: 1px solid #CCCCCC;
|
border: 1px solid #cccccc;
|
||||||
background-color: #FFFFFF;
|
background-color: #ffffff;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 200px;
|
margin-top: 200px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -65,6 +65,14 @@ WEEK OF 2018-11-05 - RAVEN shell start work. YAY!
|
|||||||
- Reporting
|
- Reporting
|
||||||
- Notifications from the server
|
- Notifications from the server
|
||||||
- File upload / download
|
- 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
|
- 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
|
- Nice transitions
|
||||||
- Some sample charts
|
- 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:
|
Here is an example of how to structure a non trivial application with VUEX broken into modules:
|
||||||
https://vuex.vuejs.org/guide/structure.html
|
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
|
SERVICEWORKER = WORKBOX
|
||||||
=-=-=-=-=-=-=-=-=-=-=-=
|
=-=-=-=-=-=-=-=-=-=-=-=
|
||||||
For offsite PWA use, works well and is simple to implement
|
For offsite PWA use, works well and is simple to implement
|
||||||
|
|||||||
Reference in New Issue
Block a user