persistant storage for vuex, logging instead of console.log, profile support

This commit is contained in:
Tobias Kurze
2019-04-05 13:44:59 +02:00
parent 5332940a5b
commit 91edb27529
9 changed files with 213 additions and 53 deletions

18
src/$log.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
import Vue from 'vue';
/*
Type augmentation for log plugin for typescript
https://vuejs.org/v2/guide/typescript.html#Augmenting-Types-for-Use-with-Plugins
https://github.com/justinkames/vuejs-logger/issues/24
Tobias
*/
declare module 'vue/types/vue' {
export interface VueConstructor<V extends Vue = Vue> {
$log: {
debug(...args: any[]): void;
info(...args: any[]): void;
warn(...args: any[]): void;
error(...args: any[]): void;
fatal(...args: any[]): void;
};
}
}

View File

@@ -3,7 +3,8 @@
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/login">Login</router-link>
<router-link to="/login">Login</router-link> |
<router-link to="/profile">Profile</router-link>
</div>
<router-view/>
</div>

View File

@@ -1,46 +1,51 @@
import Vue from 'vue';
import axios from 'axios';
const API_URL = 'http://localhost:5443/api';
export function fetchSurveys () {
return axios.get(`${API_URL}/surveys/`)
export function fetchSurveys() {
return axios.get(`${API_URL}/surveys/`);
}
export function fetchSurvey (surveyId: string) {
return axios.get(`${API_URL}/surveys/${surveyId}/`)
export function fetchSurvey(surveyId: string) {
return axios.get(`${API_URL}/surveys/${surveyId}/`);
}
export function saveSurveyResponse (surveyResponse: any) {
return axios.put(`${API_URL}/surveys/${surveyResponse.id}/`, surveyResponse)
export function saveSurveyResponse(surveyResponse: any) {
return axios.put(`${API_URL}/surveys/${surveyResponse.id}/`, surveyResponse);
}
export function postNewSurvey (survey: any, jwt: any) {
return axios.post(`${API_URL}/surveys/`, survey, { headers: { Authorization: `Bearer ${jwt}` } })
export function postNewSurvey(survey: any, jwt: any) {
return axios.post(`${API_URL}/surveys/`, survey, { headers: { Authorization: `Bearer ${jwt}` } });
}
export function authenticate (userData: any) {
return axios.post(`${API_URL}/auth/login`, userData)
export function authenticate(userData: any) {
return axios.post(`${API_URL}/auth/login`, userData);
}
export function register (userData: any) {
return axios.post(`${API_URL}/auth/register`, userData)
export function register(userData: any) {
return axios.post(`${API_URL}/auth/register`, userData);
}
// This function probably isn't really useful here, as a user must be redirected to the actual OIDC provider.
// -> So login involves user interaction through the frontend (and not just API calls).
export function oidc_login (redirection_url: any) {
return axios.get(`${API_URL}/auth/oidc`, redirection_url)
export function oidc_login(redirectionUrl: any) {
return axios.get(`${API_URL}/auth/oidc`, redirectionUrl);
}
export function getFreshToken (refresh_token: any) {
return axios.get(`${API_URL}/auth/fresh`, refresh_token)
export function getFreshToken(refreshToken: any) {
return axios.get(`${API_URL}/auth/fresh`, refreshToken);
}
export function getProviders () {
return axios.get(`${API_URL}/auth/providers`)
export function getProviders() {
return axios.get(`${API_URL}/auth/providers`);
}
export function fetchUsers (jwt: any) {
console.log("JWT: " + jwt);
return axios.get(`${API_URL}/v1/user`, { headers: { Authorization: `Bearer ${jwt}` } })
export function fetchUsers(jwt: any) {
return axios.get(`${API_URL}/v1/user`, { headers: { Authorization: `Bearer ${jwt}` } });
}
export function fetchProfile(jwt: any) {
Vue.$log.debug("JWT: "+ jwt);
return axios.get(`${API_URL}/v1/user/profile`, { headers: { Authorization: `Bearer ${jwt}` } });
}

View File

@@ -0,0 +1,58 @@
<!-- components/Profile.vue -->
<template>
<div>
<section class="hero is-primary">
<div class="hero-body">
<div class="container has-text-centered">
<h2 class="title">Profile</h2>
<p>{{profile.id}}</p>
<p class="subtitle error-msg">{{ errorMsg }}</p>
</div>
</div>
</section>
</div>
</template>
<script>
import { EventBus } from '@/utils'
export default {
data () {
return {
email: '',
errorMsg: '',
};
},
methods: {
authenticate () {
this.$store.dispatch('login', { email: this.email, password: this.password })
.then(() => this.$router.push('/'));
},
},
mounted () {
this.$log.debug("Profile: mounting...");
EventBus.$on('failedLoadingProfile', (msg) => {
this.errorMsg = msg;
});
this.$store.dispatch('loadProfile');
},
beforeDestroy () {
EventBus.$off('failedLoadingProfile');
},
computed: {
profile () {
return this.$store.state.profile;
},
},
}
</script>
<style lang="scss">
.error-msg {
color: red;
font-weight: bold;
}
</style>

View File

@@ -4,16 +4,31 @@ import VueAxios from 'vue-axios';
import App from './App.vue';
import router from './router';
import store from './store';
import VueCookies from 'vue-cookies'
import VueCookies from 'vue-cookies';
import VueLogger from 'vuejs-logger';
import i18n from '@/plugins/i18n';
// @ts-ignore
import FlagIcon from 'vue-flag-icon';
// following is to avoid missing type definitions
// const FlagIcon = require('vue-flag-icon');
const isProduction = process.env.NODE_ENV === 'production';
const options = {
isEnabled: true,
// logLevel : isProduction ? 'error' : 'debug',
logLevel : 'debug',
stringifyArguments : false,
showLogLevel : true,
showMethodName : true,
separator: '|',
showConsoleColors: true
};
Vue.use(VueLogger, options);
Vue.use(VueAxios, axios);
Vue.use(FlagIcon);
Vue.use(VueCookies)
Vue.use(VueCookies);
// setup fake backend
// import { configureFakeBackend } from './helpers';

View File

@@ -6,6 +6,7 @@ import NotFound from './views/NotFound.vue';
import Survey from '@/components/Survey.vue';
import NewSurvey from '@/components/NewSurvey.vue';
import Login from '@/components/Login.vue';
import Profile from '@/components/Profile.vue';
import store from '@/store';
Vue.use(Router);
@@ -22,6 +23,7 @@ export const router = new Router({
},
{
path: '/login',
name: 'Login',
component: Login,
},
{
@@ -47,9 +49,9 @@ export const router = new Router({
}
},
}, {
path: '/login',
name: 'Login',
component: Login,
path: '/profile',
name: 'Profile',
component: Profile,
},
{
path: '*',

View File

@@ -1,6 +1,6 @@
import Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate'
// imports of AJAX functions will go here
import {
@@ -11,7 +11,7 @@ import {
postNewSurvey,
authenticate,
register,
oidc_login, fetchUsers, getFreshToken
oidc_login, fetchUsers, getFreshToken, fetchProfile,
} from '@/api';
import { isValidJwt, EventBus } from '@/utils';
@@ -22,7 +22,7 @@ const state = {
surveys: [],
loginProviders: [],
currentSurvey: {},
user: {},
profile: {},
users: [],
access_token: '',
refresh_token: '',
@@ -51,51 +51,64 @@ const actions = {
loadUsers(context: any) {
return fetchUsers(context.state.access_token)
.then((response) => {
console.log(response);
console.log(response.data);
Vue.$log.debug(response);
Vue.$log.debug(response.data);
context.commit('setUsers', { users: response.data });
EventBus.$emit('usersLoaded', response.data);
})
.catch((error) => {
console.log('Error loading users!', error);
Vue.$log.warn('Error loading users!', error);
EventBus.$emit('failedLoadingUsers', error);
});
},
loadProfile(context: any) {
return fetchProfile(context.state.access_token)
.then((response) => {
Vue.$log.debug(response);
Vue.$log.debug(response.data);
context.commit('setProfile', { profile: response.data });
EventBus.$emit('profileLoaded', response.data);
})
.catch((error) => {
Vue.$log.warn('Error loading profile!', error);
EventBus.$emit('failedLoadingProfile', error);
});
},
loadLoginProviders(context: any) {
return getProviders()
.then((response) => {
context.commit('setLoginProviderData', {providers: response.data});
EventBus.$emit('loginProvidersLoaded', response.data);
})
});
},
login(context: any, userData: any) {
context.commit('setUserData', { userData });
return authenticate(userData)
.then((response) => context.commit('setJwtToken', { tokens: response.data }))
.catch((error) => {
console.log('Error Authenticating: ', error);
Vue.$log.warn('Error Authenticating: ', error);
EventBus.$emit('failedAuthentication', error);
});
},
oidc_login(context: any, redirection_url: any) {
//context.commit('setUserData', { userData });
return oidc_login(redirection_url)
oidc_login(context: any, redirectionUrl: any) {
// context.commit('setUserData', { userData });
return oidc_login(redirectionUrl)
.then((response) => context.commit('setJwtToken', { tokens: response.data }))
.catch((error) => {
console.log('Error Authenticating: ', error);
Vue.$log.warn('Error Authenticating: ', error);
EventBus.$emit('failedAuthentication', error);
});
},
refreshToken(context: any) {
//context.commit('setUserData', { userData });
// context.commit('setUserData', { userData });
return getFreshToken(context.state.refresh_token)
.then((response) => context.commit('setTokens', { tokens: response.data }))
.catch((error) => {
console.log('Error Refreshing token: ', error);
Vue.$log.warn('Error Refreshing token: ', error);
EventBus.$emit('failedRefreshingToken', error);
});
},
storeTokens(context: any, tokens: any){
storeTokens(context: any, tokens: any) {
context.commit('setTokens', {tokens});
EventBus.$emit('storedTokens');
},
@@ -104,7 +117,7 @@ const actions = {
return register(userData)
.then(context.dispatch('login', userData))
.catch((error) => {
console.log('Error Registering: ', error);
Vue.$log.warn('Error Registering: ', error);
EventBus.$emit('failedRegistering: ', error);
});
},
@@ -138,33 +151,38 @@ const mutations = {
}
}
},
setLoginProviderData(sState: any, payload: any){
console.log("got loginProviders = ", payload);
setLoginProviderData(sState: any, payload: any) {
Vue.$log.debug('got loginProviders = ', payload);
sState.loginProviders = payload.providers;
},
// probably old ...
setUserData(sState: any, payload: any) {
console.log('setUserData payload = ', payload);
Vue.$log.debug('setUserData payload = ', payload);
sState.userData = payload.userData;
},
setProfile(sState: any, payload: any) {
Vue.$log.debug('setProfile payload = ', payload);
sState.profile = payload.profile;
},
setJwtToken(sState: any, payload: any) {
console.log('setJwtToken payload = ', payload);
Vue.$log.debug('setJwtToken payload = ', payload);
localStorage.tokens = payload.tokens;
sState.jwt = payload.tokens.access_token;
sState.jwt_refresh_token = payload.tokens.refresh_token;
},
setTokens(sState: any, payload:any){
console.log('setTokens payload = ', payload);
setTokens(sState: any, payload: any) {
Vue.$log.debug('setTokens payload = ', payload);
sState.access_token = payload.tokens.access_token;
sState.refresh_token = payload.tokens.refresh_token;
console.log(sState.access_token);
console.log(sState.access_token);
}
Vue.$log.debug(sState.access_token);
Vue.$log.debug(sState.access_token);
},
};
const getters = {
// reusable data accessors
isAuthenticated(sState: any) {
return isValidJwt(sState.jwt.token);
return isValidJwt(sState.access_token);
},
getLoginProviders(sState: any) {
return sState.loginProviders;
@@ -176,6 +194,7 @@ const store = new Vuex.Store({
actions,
mutations,
getters,
plugins: [createPersistedState()],
});
export default store;