This commit is contained in:
2018-11-05 23:36:46 +00:00
parent a198bfcfb9
commit a9e8bfdaa3
8 changed files with 209 additions and 70 deletions

View File

@@ -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",

View File

@@ -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/"
}
}
}

View File

@@ -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()
}
})

View File

@@ -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: {}

View 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();
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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