removed crappy test login files
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
<div id="app">
|
<div id="app">
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
<router-link to="/">Home</router-link> |
|
<router-link to="/">Home</router-link> |
|
||||||
<router-link to="/about">About</router-link>
|
<router-link to="/about">About</router-link> |
|
||||||
|
<router-link to="/login">Login</router-link>
|
||||||
</div>
|
</div>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
}
|
}About
|
||||||
#nav {
|
#nav {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -43,31 +43,31 @@
|
|||||||
return {
|
return {
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
errorMsg: ''
|
errorMsg: '',
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
authenticate () {
|
authenticate () {
|
||||||
this.$store.dispatch('login', { email: this.email, password: this.password })
|
this.$store.dispatch('login', { email: this.email, password: this.password })
|
||||||
.then(() => this.$router.push('/'))
|
.then(() => this.$router.push('/'));
|
||||||
},
|
},
|
||||||
register () {
|
register () {
|
||||||
this.$store.dispatch('register', { email: this.email, password: this.password })
|
this.$store.dispatch('register', { email: this.email, password: this.password })
|
||||||
.then(() => this.$router.push('/'))
|
.then(() => this.$router.push('/'));
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
EventBus.$on('failedRegistering', (msg) => {
|
EventBus.$on('failedRegistering', (msg) => {
|
||||||
this.errorMsg = msg
|
this.errorMsg = msg
|
||||||
})
|
});
|
||||||
EventBus.$on('failedAuthentication', (msg) => {
|
EventBus.$on('failedAuthentication', (msg) => {
|
||||||
this.errorMsg = msg
|
this.errorMsg = msg
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy () {
|
beforeDestroy () {
|
||||||
EventBus.$off('failedRegistering')
|
EventBus.$off('failedRegistering');
|
||||||
EventBus.$off('failedAuthentication')
|
EventBus.$off('failedAuthentication');
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
export function authHeader() {
|
|
||||||
// return authorization header with jwt token
|
|
||||||
// @ts-ignore
|
|
||||||
let user = JSON.parse(localStorage.getItem('user'));
|
|
||||||
|
|
||||||
if (user && user.token) {
|
|
||||||
return { 'Authorization': 'Bearer ' + user.token };
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
// array in local storage for registered users
|
|
||||||
// @ts-ignore
|
|
||||||
let users = JSON.parse(localStorage.getItem('users')) || [];
|
|
||||||
|
|
||||||
export function configureFakeBackend() {
|
|
||||||
let realFetch = window.fetch;
|
|
||||||
window.fetch = function (url, opts) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// wrap in timeout to simulate server api call
|
|
||||||
setTimeout(() => {
|
|
||||||
|
|
||||||
// authenticate
|
|
||||||
// @ts-ignore
|
|
||||||
if (url.endsWith('/users/authenticate') && opts.method === 'POST') {
|
|
||||||
// get parameters from post request
|
|
||||||
// @ts-ignore
|
|
||||||
let params = JSON.parse(opts.body);
|
|
||||||
|
|
||||||
// find if any user matches login credentials
|
|
||||||
let filteredUsers = users.filter((user: any) => {
|
|
||||||
return user.username === params.username && user.password === params.password;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (filteredUsers.length) {
|
|
||||||
// if login details are valid return user details and fake jwt token
|
|
||||||
let user = filteredUsers[0];
|
|
||||||
let responseJson = {
|
|
||||||
id: user.id,
|
|
||||||
username: user.username,
|
|
||||||
firstName: user.firstName,
|
|
||||||
lastName: user.lastName,
|
|
||||||
token: 'fake-jwt-token'
|
|
||||||
};
|
|
||||||
// @ts-ignore
|
|
||||||
resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(responseJson)) });
|
|
||||||
} else {
|
|
||||||
// else return error
|
|
||||||
reject('Username or password is incorrect');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get users
|
|
||||||
// @ts-ignore
|
|
||||||
if (url.endsWith('/users') && opts.method === 'GET') {
|
|
||||||
// check for fake auth token in header and return users if valid, this security is implemented server side in a real application
|
|
||||||
// @ts-ignore
|
|
||||||
if (opts.headers && opts.headers.Authorization === 'Bearer fake-jwt-token') {
|
|
||||||
// @ts-ignore
|
|
||||||
resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(users))});
|
|
||||||
} else {
|
|
||||||
// return 401 not authorised if token is null or invalid
|
|
||||||
reject('Unauthorised');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get user by id
|
|
||||||
// @ts-ignore
|
|
||||||
if (url.match(/\/users\/\d+$/) && opts.method === 'GET') {
|
|
||||||
// check for fake auth token in header and return user if valid, this security is implemented server side in a real application
|
|
||||||
// @ts-ignore
|
|
||||||
if (opts.headers && opts.headers.Authorization === 'Bearer fake-jwt-token') {
|
|
||||||
// find user by id in users array
|
|
||||||
// @ts-ignore
|
|
||||||
let urlParts = url.split('/');
|
|
||||||
let id = parseInt(urlParts[urlParts.length - 1]);
|
|
||||||
// @ts-ignore
|
|
||||||
let matchedUsers = users.filter((user) => { return user.id === id; });
|
|
||||||
let user = matchedUsers.length ? matchedUsers[0] : null;
|
|
||||||
|
|
||||||
// respond 200 OK with user
|
|
||||||
// @ts-ignore
|
|
||||||
resolve({ ok: true, text: () => JSON.stringify(user)});
|
|
||||||
} else {
|
|
||||||
// return 401 not authorised if token is null or invalid
|
|
||||||
reject('Unauthorised');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// register user
|
|
||||||
// @ts-ignore
|
|
||||||
if (url.endsWith('/users/register') && opts.method === 'POST') {
|
|
||||||
// get new user object from post body
|
|
||||||
// @ts-ignore
|
|
||||||
let newUser = JSON.parse(opts.body);
|
|
||||||
|
|
||||||
// validation
|
|
||||||
let duplicateUser = users.filter((user: any) => { return user.username === newUser.username; }).length;
|
|
||||||
if (duplicateUser) {
|
|
||||||
reject('Username "' + newUser.username + '" is already taken');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save new user
|
|
||||||
newUser.id = users.length ? Math.max(...users.map((user: any) => user.id)) + 1 : 1;
|
|
||||||
users.push(newUser);
|
|
||||||
localStorage.setItem('users', JSON.stringify(users));
|
|
||||||
|
|
||||||
// respond 200 OK
|
|
||||||
// @ts-ignore
|
|
||||||
resolve({ ok: true, text: () => Promise.resolve() });
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete user
|
|
||||||
// @ts-ignore
|
|
||||||
if (url.match(/\/users\/\d+$/) && opts.method === 'DELETE') {
|
|
||||||
// check for fake auth token in header and return user if valid, this security is implemented server side in a real application
|
|
||||||
// @ts-ignore
|
|
||||||
if (opts.headers && opts.headers.Authorization === 'Bearer fake-jwt-token') {
|
|
||||||
// find user by id in users array
|
|
||||||
// @ts-ignore
|
|
||||||
let urlParts = url.split('/');
|
|
||||||
let id = parseInt(urlParts[urlParts.length - 1]);
|
|
||||||
for (let i = 0; i < users.length; i++) {
|
|
||||||
let user = users[i];
|
|
||||||
if (user.id === id) {
|
|
||||||
// delete user
|
|
||||||
users.splice(i, 1);
|
|
||||||
localStorage.setItem('users', JSON.stringify(users));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// respond 200 OK
|
|
||||||
// @ts-ignore
|
|
||||||
resolve({ ok: true, text: () => Promise.resolve() });
|
|
||||||
} else {
|
|
||||||
// return 401 not authorised if token is null or invalid
|
|
||||||
reject('Unauthorised');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass through any requests not handled above
|
|
||||||
realFetch(url, opts).then((response) => resolve(response));
|
|
||||||
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from './fake-backend';
|
|
||||||
export * from './auth-header';
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import axios from 'axios'
|
import axios from 'axios';
|
||||||
import VueAxios from 'vue-axios'
|
import VueAxios from 'vue-axios';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import store from './store';
|
import store from './store';
|
||||||
@@ -10,7 +10,7 @@ import FlagIcon from 'vue-flag-icon';
|
|||||||
// following is to avoid missing type definitions
|
// following is to avoid missing type definitions
|
||||||
// const FlagIcon = require('vue-flag-icon');
|
// const FlagIcon = require('vue-flag-icon');
|
||||||
|
|
||||||
Vue.use(VueAxios, axios)
|
Vue.use(VueAxios, axios);
|
||||||
Vue.use(FlagIcon);
|
Vue.use(FlagIcon);
|
||||||
|
|
||||||
// setup fake backend
|
// setup fake backend
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ 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 NotFound from './views/NotFound.vue';
|
import NotFound from './views/NotFound.vue';
|
||||||
import LoginPage from './views/LoginPage.vue';
|
|
||||||
|
|
||||||
|
|
||||||
import Survey from '@/components/Survey.vue';
|
import Survey from '@/components/Survey.vue';
|
||||||
import NewSurvey from '@/components/NewSurvey.vue';
|
import NewSurvey from '@/components/NewSurvey.vue';
|
||||||
import Login from '@/components/Login.vue';
|
import Login from '@/components/Login.vue';
|
||||||
import store from '@/store'
|
import store from '@/store';
|
||||||
|
|
||||||
Vue.use(Router);
|
Vue.use(Router);
|
||||||
|
|
||||||
@@ -24,7 +22,7 @@ export const router = new Router({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: '/login',
|
||||||
component: LoginPage,
|
component: Login,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
@@ -36,22 +34,22 @@ export const router = new Router({
|
|||||||
}, {
|
}, {
|
||||||
path: '/surveys/:id',
|
path: '/surveys/:id',
|
||||||
name: 'Survey',
|
name: 'Survey',
|
||||||
component: Survey
|
component: Survey,
|
||||||
}, {
|
}, {
|
||||||
path: '/surveys',
|
path: '/surveys',
|
||||||
name: 'NewSurvey',
|
name: 'NewSurvey',
|
||||||
component: NewSurvey,
|
component: NewSurvey,
|
||||||
beforeEnter(to, from, next) {
|
beforeEnter(to, from, next) {
|
||||||
if (!store.getters.isAuthenticated) {
|
if (!store.getters.isAuthenticated) {
|
||||||
next('/login')
|
next('/login');
|
||||||
} else {
|
} else {
|
||||||
next()
|
next();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
component: Login
|
component: Login,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
@@ -61,15 +59,4 @@ export const router = new Router({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
// redirect to login page if not logged in and trying to access a restricted page
|
|
||||||
const publicPages = ['/login', '/register'];
|
|
||||||
const authRequired = !publicPages.includes(to.path);
|
|
||||||
const loggedIn = localStorage.getItem('user');
|
|
||||||
|
|
||||||
if (authRequired && !loggedIn) {
|
|
||||||
return next('/login');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export * from './user.service';
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
|
|
||||||
import { authHeader } from '@/helpers';
|
|
||||||
|
|
||||||
export const userService = {
|
|
||||||
login,
|
|
||||||
logout,
|
|
||||||
register,
|
|
||||||
getAll,
|
|
||||||
getById,
|
|
||||||
update,
|
|
||||||
delete: _delete,
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
function login(username, password) {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ username, password }),
|
|
||||||
};
|
|
||||||
|
|
||||||
return fetch(`${process.env.API_URL}/users/authenticate`, requestOptions)
|
|
||||||
.then(handleResponse)
|
|
||||||
.then((user) => {
|
|
||||||
// login successful if there's a jwt token in the response
|
|
||||||
if (user.token) {
|
|
||||||
// store user details and jwt token in local storage to keep user logged in between page refreshes
|
|
||||||
localStorage.setItem('user', JSON.stringify(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function logout() {
|
|
||||||
// remove user from local storage to log user out
|
|
||||||
localStorage.removeItem('user');
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
function register(user) {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify(user),
|
|
||||||
};
|
|
||||||
|
|
||||||
return fetch(`${process.env.API_URL}/users/register`, requestOptions).then(handleResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAll() {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'GET',
|
|
||||||
headers: authHeader(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
return fetch(`${config.apiUrl}/users`, requestOptions).then(handleResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
function getById(id) {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'GET',
|
|
||||||
headers: authHeader(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
return fetch(`${config.apiUrl}/users/${id}`, requestOptions).then(handleResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
function update(user) {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: { ...authHeader(), 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify(user),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
return fetch(`${config.apiUrl}/users/${user.id}`, requestOptions).then(handleResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefixed function name with underscore because delete is a reserved word in javascript
|
|
||||||
// @ts-ignore
|
|
||||||
function _delete(id) {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: authHeader(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
return fetch(`${config.apiUrl}/users/${id}`, requestOptions).then(handleResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
function handleResponse(response) {
|
|
||||||
return response.text().then((text: any) => {
|
|
||||||
const data = text && JSON.parse(text);
|
|
||||||
if (!response.ok) {
|
|
||||||
if (response.status === 401) {
|
|
||||||
// auto logout if 401 response returned from api
|
|
||||||
logout();
|
|
||||||
location.reload(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const error = (data && data.message) || response.statusText;
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
104
src/store.ts
104
src/store.ts
@@ -3,8 +3,8 @@ import Vuex from 'vuex';
|
|||||||
|
|
||||||
|
|
||||||
// imports of AJAX functions will go here
|
// imports of AJAX functions will go here
|
||||||
import { fetchSurveys, fetchSurvey, saveSurveyResponse, postNewSurvey, authenticate, register } from '@/api'
|
import { fetchSurveys, fetchSurvey, saveSurveyResponse, postNewSurvey, authenticate, register } from '@/api';
|
||||||
import { isValidJwt, EventBus } from '@/utils'
|
import { isValidJwt, EventBus } from '@/utils';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
@@ -13,98 +13,96 @@ const state = {
|
|||||||
surveys: [],
|
surveys: [],
|
||||||
currentSurvey: {},
|
currentSurvey: {},
|
||||||
user: {},
|
user: {},
|
||||||
jwt: ''
|
jwt: '',
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
// asynchronous operations
|
// asynchronous operations
|
||||||
loadSurveys(context: any) {
|
loadSurveys(context: any) {
|
||||||
return fetchSurveys()
|
return fetchSurveys()
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
context.commit('setSurveys', { surveys: response.data })
|
context.commit('setSurveys', { surveys: response.data });
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
loadSurvey(context: any, { id }) {
|
loadSurvey(context: any, { id }) {
|
||||||
return fetchSurvey(id)
|
return fetchSurvey(id)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
context.commit('setSurvey', { survey: response.data })
|
context.commit('setSurvey', { survey: response.data });
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
addSurveyResponse(context: any) {
|
addSurveyResponse(context: any) {
|
||||||
return saveSurveyResponse(context.state.currentSurvey)
|
return saveSurveyResponse(context.state.currentSurvey);
|
||||||
},
|
},
|
||||||
|
|
||||||
login(context: any, userData: any) {
|
login(context: any, userData: any) {
|
||||||
context.commit('setUserData', { userData })
|
context.commit('setUserData', { userData });
|
||||||
return authenticate(userData)
|
return authenticate(userData)
|
||||||
.then(response => context.commit('setJwtToken', { jwt: response.data }))
|
.then((response) => context.commit('setJwtToken', { jwt: response.data }))
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.log('Error Authenticating: ', error)
|
console.log('Error Authenticating: ', error);
|
||||||
// @ts-ignore
|
EventBus.$emit('failedAuthentication', error);
|
||||||
EventBus.emit('failedAuthentication', error)
|
});
|
||||||
})
|
|
||||||
},
|
},
|
||||||
register(context: any, userData: any) {
|
register(context: any, userData: any) {
|
||||||
context.commit('setUserData', { userData })
|
context.commit('setUserData', { userData });
|
||||||
return register(userData)
|
return register(userData)
|
||||||
.then(context.dispatch('login', userData))
|
.then(context.dispatch('login', userData))
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
console.log('Error Registering: ', error)
|
console.log('Error Registering: ', error);
|
||||||
// @ts-ignore
|
EventBus.$emit('failedRegistering: ', error);
|
||||||
EventBus.emit('failedRegistering: ', error)
|
});
|
||||||
})
|
|
||||||
},
|
},
|
||||||
submitNewSurvey(context: any, survey: any) {
|
submitNewSurvey(context: any, survey: any) {
|
||||||
return postNewSurvey(survey, context.state.jwt.token)
|
return postNewSurvey(survey, context.state.jwt.token);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
// isolated data mutations
|
// isolated data mutations
|
||||||
setSurveys (state: any, payload: any) {
|
setSurveys(sState: any, payload: any) {
|
||||||
state.surveys = payload.surveys
|
sState.surveys = payload.surveys;
|
||||||
},
|
},
|
||||||
setSurvey (state: any, payload: any) {
|
setSurvey(sState: any, payload: any) {
|
||||||
const nQuestions = payload.survey.questions.length
|
const nQuestions = payload.survey.questions.length;
|
||||||
for (let i = 0; i < nQuestions; i++) {
|
for (let i = 0; i < nQuestions; i++) {
|
||||||
payload.survey.questions[i].choice = null
|
payload.survey.questions[i].choice = null;
|
||||||
}
|
}
|
||||||
state.currentSurvey = payload.survey
|
sState.currentSurvey = payload.survey;
|
||||||
},
|
},
|
||||||
setChoice (state: any, payload: any) {
|
setChoice(sState: any, payload: any) {
|
||||||
const { questionId, choice } = payload
|
const { questionId, choice } = payload;
|
||||||
const nQuestions = state.currentSurvey.questions.length
|
const nQuestions = sState.currentSurvey.questions.length;
|
||||||
for (let i = 0; i < nQuestions; i++) {
|
for (let i = 0; i < nQuestions; i++) {
|
||||||
if (state.currentSurvey.questions[i].id === questionId) {
|
if (sState.currentSurvey.questions[i].id === questionId) {
|
||||||
state.currentSurvey.questions[i].choice = choice
|
sState.currentSurvey.questions[i].choice = choice;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setUserData (state: any, payload: any) {
|
setUserData(sState: any, payload: any) {
|
||||||
console.log('setUserData payload = ', payload)
|
console.log('setUserData payload = ', payload);
|
||||||
state.userData = payload.userData
|
sState.userData = payload.userData;
|
||||||
},
|
},
|
||||||
setJwtToken (state: any, payload: any) {
|
setJwtToken(sState: any, payload: any) {
|
||||||
console.log('setJwtToken payload = ', payload)
|
console.log('setJwtToken payload = ', payload);
|
||||||
localStorage.token = payload.jwt.token
|
localStorage.token = payload.jwt.token;
|
||||||
state.jwt = payload.jwt
|
sState.jwt = payload.jwt;
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
// reusable data accessors
|
// reusable data accessors
|
||||||
isAuthenticated (state: any) {
|
isAuthenticated(sState: any) {
|
||||||
return isValidJwt(state.jwt.token)
|
return isValidJwt(sState.jwt.token);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
state,
|
state,
|
||||||
actions,
|
actions,
|
||||||
mutations,
|
mutations,
|
||||||
getters
|
getters,
|
||||||
})
|
});
|
||||||
|
|
||||||
export default store
|
export default store;
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
import { userService } from '@/services';
|
|
||||||
import { router } from '@/router';
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const user = JSON.parse(localStorage.getItem('user'));
|
|
||||||
const state = user
|
|
||||||
? { status: { loggedIn: true }, user }
|
|
||||||
: { status: {}, user: null };
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
// @ts-ignore
|
|
||||||
login({ dispatch, commit }, { username, password }) {
|
|
||||||
commit('loginRequest', { username });
|
|
||||||
|
|
||||||
userService.login(username, password)
|
|
||||||
.then(
|
|
||||||
(loggedInUser) => {
|
|
||||||
commit('loginSuccess', loggedInUser);
|
|
||||||
router.push('/');
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
commit('loginFailure', error);
|
|
||||||
dispatch('alert/error', error, { root: true });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
logout({ commit }) {
|
|
||||||
userService.logout();
|
|
||||||
commit('logout');
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
register({ dispatch, commit }, userToRegister) {
|
|
||||||
commit('registerRequest', userToRegister);
|
|
||||||
|
|
||||||
userService.register(userToRegister)
|
|
||||||
.then(
|
|
||||||
(registeredUser) => {
|
|
||||||
commit('registerSuccess', registeredUser);
|
|
||||||
router.push('/login');
|
|
||||||
setTimeout(() => {
|
|
||||||
// display success message after route change completes
|
|
||||||
dispatch('alert/success', 'Registration successful', { root: true });
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
commit('registerFailure', error);
|
|
||||||
dispatch('alert/error', error, { root: true });
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
// @ts-ignore
|
|
||||||
loginRequest(mutState, userToLogin) {
|
|
||||||
mutState.status = { loggingIn: true };
|
|
||||||
mutState.user = userToLogin;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
loginSuccess(mutState, userToLogin) {
|
|
||||||
mutState.status = { loggedIn: true };
|
|
||||||
mutState.user = userToLogin;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
loginFailure(mutState) {
|
|
||||||
mutState.status = {};
|
|
||||||
mutState.user = null;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
logout(mutState) {
|
|
||||||
mutState.status = {};
|
|
||||||
mutState.user = null;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
registerRequest(mutState, userToRegister) {
|
|
||||||
mutState.status = { registering: true };
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
registerSuccess(mutState, userToRegister) {
|
|
||||||
mutState.status = {};
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
registerFailure(mutState, error) {
|
|
||||||
mutState.status = {};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const account = {
|
|
||||||
namespaced: true,
|
|
||||||
state,
|
|
||||||
actions,
|
|
||||||
mutations,
|
|
||||||
};
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
const state = {
|
|
||||||
type: null,
|
|
||||||
message: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
// @ts-ignore
|
|
||||||
success({ commit }, message) {
|
|
||||||
commit('success', message);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
error({ commit }, message) {
|
|
||||||
commit('error', message);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
clear({ commit }, message) {
|
|
||||||
commit('success', message);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
// @ts-ignore
|
|
||||||
success(mutState, message) {
|
|
||||||
mutState.type = 'alert-success';
|
|
||||||
mutState.message = message;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
error(mutState, message) {
|
|
||||||
mutState.type = 'alert-danger';
|
|
||||||
mutState.message = message;
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
clear(mutState) {
|
|
||||||
mutState.type = null;
|
|
||||||
mutState.message = null;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const alert = {
|
|
||||||
namespaced: true,
|
|
||||||
state,
|
|
||||||
actions,
|
|
||||||
mutations,
|
|
||||||
};
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
import { userService } from '@/services';
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
all: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
// @ts-ignore
|
|
||||||
getAll({ commit }) {
|
|
||||||
commit('getAllRequest');
|
|
||||||
|
|
||||||
userService.getAll()
|
|
||||||
.then(
|
|
||||||
(receivedUsers: any) => commit('getAllSuccess', receivedUsers),
|
|
||||||
(error: any) => commit('getAllFailure', error),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
delete({ commit }, id) {
|
|
||||||
commit('deleteRequest', id);
|
|
||||||
|
|
||||||
userService.delete(id)
|
|
||||||
.then(
|
|
||||||
(user: any) => commit('deleteSuccess', id),
|
|
||||||
(error: any) => commit('deleteSuccess', { id, error: error.toString() }),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const mutations = {
|
|
||||||
// @ts-ignore
|
|
||||||
getAllRequest(mutState) {
|
|
||||||
mutState.all = { loading: true };
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
getAllSuccess(mutState, receivedUsers) {
|
|
||||||
mutState.all = { items: receivedUsers };
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
getAllFailure(mutState, error) {
|
|
||||||
mutState.all = { error };
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
deleteRequest(mutState, id) {
|
|
||||||
// add 'deleting:true' property to user being deleted
|
|
||||||
mutState.all.items = mutState.all.items.map((user: any) =>
|
|
||||||
user.id === id
|
|
||||||
? { ...user, deleting: true }
|
|
||||||
: user,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
deleteSuccess(mutState, id) {
|
|
||||||
// remove deleted user from state
|
|
||||||
mutState.all.items = mutState.all.items.filter((user: any) => user.id !== id);
|
|
||||||
},
|
|
||||||
// @ts-ignore
|
|
||||||
deleteFailure(mutState, { id, error }) {
|
|
||||||
// remove 'deleting:true' property and add 'deleteError:[error]' property to user
|
|
||||||
mutState.all.items = mutState.items.map((user: any) => {
|
|
||||||
if (user.id === id) {
|
|
||||||
// make copy of user without 'deleting:true' property
|
|
||||||
const { deleting, ...userCopy } = user;
|
|
||||||
// return copy of user with 'deleteError:[error]' property
|
|
||||||
return { ...userCopy, deleteError: error };
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const users = {
|
|
||||||
namespaced: true,
|
|
||||||
state,
|
|
||||||
actions,
|
|
||||||
mutations,
|
|
||||||
};
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// utils/index.js
|
// utils/index.js
|
||||||
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue';
|
||||||
|
|
||||||
export const EventBus = new Vue();
|
export const EventBus = new Vue();
|
||||||
|
|
||||||
export function isValidJwt(jwt: any) {
|
export function isValidJwt(jwt: any) {
|
||||||
if (!jwt || jwt.split('.').length < 3) {
|
if (!jwt || jwt.split('.').length < 3) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
const data = JSON.parse(atob(jwt.split('.')[1]));
|
const data = JSON.parse(atob(jwt.split('.')[1]));
|
||||||
const exp = new Date(data.exp * 1000);
|
const exp = new Date(data.exp * 1000);
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h1>Hi {{account.user.firstName}}!</h1>
|
|
||||||
<p>You're logged in with Vue + Vuex & JWT!!</p>
|
|
||||||
<h3>Users from secure api end point:</h3>
|
|
||||||
<em v-if="users.loading">Loading users...</em>
|
|
||||||
<span v-if="users.error" class="text-danger">ERROR: {{users.error}}</span>
|
|
||||||
<ul v-if="users.items">
|
|
||||||
<li v-for="user in users.items" :key="user.id">
|
|
||||||
{{user.firstName + ' ' + user.lastName}}
|
|
||||||
<span v-if="user.deleting"><em> - Deleting...</em></span>
|
|
||||||
<span v-else-if="user.deleteError" class="text-danger"> - ERROR: {{user.deleteError}}</span>
|
|
||||||
<span v-else> - <a @click="deleteUser(user.id)" class="text-danger">Delete</a></span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<router-link to="/login">Logout</router-link>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapActions } from 'vuex';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
account: (state) => state.account,
|
|
||||||
users: (state) => state.users.all,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.getAllUsers();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions('users', {
|
|
||||||
getAllUsers: 'getAll',
|
|
||||||
deleteUser: 'delete',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div class="alert alert-info">
|
|
||||||
Username: test<br />
|
|
||||||
Password: test
|
|
||||||
</div>
|
|
||||||
<h2>Login</h2>
|
|
||||||
<form @submit.prevent="handleSubmit">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username">Username</label>
|
|
||||||
<input type="text" v-model="username" name="username" class="form-control" :class="{ 'is-invalid': submitted && !username }" />
|
|
||||||
<div v-show="submitted && !username" class="invalid-feedback">Username is required</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label htmlFor="password">Password</label>
|
|
||||||
<input type="password" v-model="password" name="password" class="form-control" :class="{ 'is-invalid': submitted && !password }" />
|
|
||||||
<div v-show="submitted && !password" class="invalid-feedback">Password is required</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-primary" :disabled="loading">Login</button>
|
|
||||||
<img v-show="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
|
|
||||||
</div>
|
|
||||||
<div v-if="error" class="alert alert-danger">{{error}}</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import router from '@/router/';
|
|
||||||
import { userService } from '@/services';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
submitted: false,
|
|
||||||
loading: false,
|
|
||||||
returnUrl: '',
|
|
||||||
error: '',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
// reset login status
|
|
||||||
userService.logout();
|
|
||||||
|
|
||||||
// get return url from route parameters or default to '/'
|
|
||||||
this.returnUrl = this.$route.query.returnUrl || '/';
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleSubmit(e) {
|
|
||||||
this.submitted = true;
|
|
||||||
const { username, password } = this;
|
|
||||||
|
|
||||||
// stop here if form is invalid
|
|
||||||
if (!(username && password)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loading = true;
|
|
||||||
userService.login(username, password)
|
|
||||||
.then(
|
|
||||||
(user) => router.push(this.returnUrl),
|
|
||||||
(error) => {
|
|
||||||
this.error = error;
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<h2>Register</h2>
|
|
||||||
<form @submit.prevent="handleSubmit">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="firstName">First Name</label>
|
|
||||||
<input type="text" v-model="user.firstName" v-validate="'required'" name="firstName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('firstName') }" />
|
|
||||||
<div v-if="submitted && errors.has('firstName')" class="invalid-feedback">{{ errors.first('firstName') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="lastName">Last Name</label>
|
|
||||||
<input type="text" v-model="user.lastName" v-validate="'required'" name="lastName" class="form-control" :class="{ 'is-invalid': submitted && errors.has('lastName') }" />
|
|
||||||
<div v-if="submitted && errors.has('lastName')" class="invalid-feedback">{{ errors.first('lastName') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username">Username</label>
|
|
||||||
<input type="text" v-model="user.username" v-validate="'required'" name="username" class="form-control" :class="{ 'is-invalid': submitted && errors.has('username') }" />
|
|
||||||
<div v-if="submitted && errors.has('username')" class="invalid-feedback">{{ errors.first('username') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label htmlFor="password">Password</label>
|
|
||||||
<input type="password" v-model="user.password" v-validate="{ required: true, min: 6 }" name="password" class="form-control" :class="{ 'is-invalid': submitted && errors.has('password') }" />
|
|
||||||
<div v-if="submitted && errors.has('password')" class="invalid-feedback">{{ errors.first('password') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<button class="btn btn-primary" :disabled="status.registering">Register</button>
|
|
||||||
<img v-show="status.registering" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
|
|
||||||
<router-link to="/login" class="btn btn-link">Cancel</router-link>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapState, mapActions } from 'vuex';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
user: {
|
|
||||||
firstName: '',
|
|
||||||
lastName: '',
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
},
|
|
||||||
submitted: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState('account', ['status']),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions('account', ['register']),
|
|
||||||
handleSubmit(e) {
|
|
||||||
this.submitted = true;
|
|
||||||
this.$validator.validate().then((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.register(this.user);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
Reference in New Issue
Block a user