Allow multiple identities (accounts actors) for one user.

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2018-07-10 10:00:07 +02:00
parent a71b81af91
commit dee437e4f3
45 changed files with 155 additions and 156 deletions

View File

@@ -12,24 +12,24 @@
<v-list-group
value="false"
>
<v-list-tile avatar v-if="$store.state.user" slot="activator">
<v-list-tile avatar v-if="$store.state.actor" slot="activator">
<v-list-tile-avatar>
<img v-if="!getUser().actor.avatar_url"
<img v-if="!$store.state.actor.avatar"
class="img-circle elevation-7 mb-1"
src="https://picsum.photos/125/125/"
>
<img v-else
class="img-circle elevation-7 mb-1"
:src="getUser().actor.avatar_url"
:src="$store.state.actor.avatar"
>
</v-list-tile-avatar>
<v-list-tile-content @click="$router.push({name: 'Account', params: { name: getUser().actor.username }})">
<v-list-tile-content @click="$router.push({name: 'Account', params: { name: $store.state.actor.username }})">
<v-list-tile-title>{{ this.displayed_name }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile avatar v-if="$store.state.user">
<v-list-tile avatar v-if="$store.state.actor">
<v-list-tile-avatar>
<img
class="img-circle elevation-7 mb-1"
@@ -177,7 +177,7 @@ export default {
},
computed: {
displayed_name() {
return this.$store.state.user.actor.display_name === null ? this.$store.state.user.actor.username : this.$store.state.user.actor.display_name
return this.$store.state.actor.display_name === null ? this.$store.state.actor.username : this.$store.state.actor.display_name
},
}
};

View File

@@ -1,4 +1,5 @@
import { API_ORIGIN, API_PATH } from '../api/_entrypoint';
import { LOGIN_USER, LOAD_USER, CHANGE_ACTOR } from '../store/mutation-types';
// URL and endpoint constants
const LOGIN_URL = `${API_ORIGIN}${API_PATH}/login`;
@@ -53,7 +54,7 @@ export default {
.then((response) => {
console.log('We have a new token');
this.authenticated = true;
store.commit('LOGIN_USER', response);
store.commit(LOGIN_USER, response);
localStorage.setItem('token', response.token);
console.log("Let's try to auth again");
successHandler();
@@ -104,9 +105,10 @@ export default {
}).then((response) => {
this.authenticated = true;
console.log(response);
store.commit('LOAD_USER', response.data);
store.commit(LOAD_USER, response.data);
store.commit(CHANGE_ACTOR, response.data.actors[0]);
return successHandler();
});
});
},
// The object to be passed as a header for authenticated requests

View File

@@ -10,7 +10,7 @@
<v-icon>chevron_left</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn icon class="mr-3" v-if="$store.state.user && $store.state.user.actor.id === actor.id">
<v-btn icon class="mr-3" v-if="$store.state.user && $store.state.actor.id === actor.id">
<v-icon>edit</v-icon>
</v-btn>
<v-menu bottom left>
@@ -18,10 +18,10 @@
<v-icon>more_vert</v-icon>
</v-btn>
<v-list>
<v-list-tile @click="logoutUser()" v-if="$store.state.user && $store.state.user.actor.id === actor.id">
<v-list-tile @click="logoutUser()" v-if="$store.state.user && $store.state.actor.id === actor.id">
<v-list-tile-title>User logout</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="deleteAccount()" v-if="$store.state.user && $store.state.user.actor.id === actor.id">
<v-list-tile @click="deleteAccount()" v-if="$store.state.user && $store.state.actor.id === actor.id">
<v-list-tile-title>Delete</v-list-tile-title>
</v-list-tile>
</v-list>
@@ -30,13 +30,13 @@
<v-spacer></v-spacer>
<div class="text-xs-center">
<v-avatar size="125px">
<img v-if="!actor.avatar_url"
<img v-if="!actor.avatar"
class="img-circle elevation-7 mb-1"
src="https://picsum.photos/125/125/"
>
<img v-else
class="img-circle elevation-7 mb-1"
:src="actor.avatar_url"
:src="actor.avatar"
>
</v-avatar>
</div>

View File

@@ -60,6 +60,7 @@
<script>
import { LOGIN_USER } from '@/store/mutation-types';
import auth from '@/auth/index';
import Gravatar from 'vue-gravatar';
import RegisterAvatar from './RegisterAvatar';
@@ -119,7 +120,7 @@
loginAction(e) {
e.preventDefault();
auth.login(JSON.stringify(this.credentials), (data) => {
this.$store.commit('LOGIN_USER', data.user);
this.$store.commit(LOGIN_USER, data.user);
this.$router.push({ name: 'Home' });
}, (error) => {
Promise.resolve(error).then((errorMsg) => {

View File

@@ -1,17 +1,18 @@
<template>
<b-container>
<v-container>
<h1 v-if="loading">{{ $t('registration.validation.process') }}</h1>
<div v-else>
<div v-if="failed">
<b-alert show variant="danger">{{ $t('registration.success.validation_failure') }}</b-alert>
<v-alert :value="true" variant="danger">Error while validating account</v-alert>
</div>
<h1 v-else>{{ $t('registration.validation.finished') }}</h1>
</div>
</b-container>
</v-container>
</template>
<script>
import fetchStory from '@/api/eventFetch';
import { LOGIN_USER } from '@/store/mutation-types';
export default {
name: 'Validate',
@@ -36,7 +37,7 @@ export default {
this.loading = false;
localStorage.setItem('token', data.token);
localStorage.setItem('refresh_token', data.refresh_token);
this.$store.commit('LOGIN_USER', data.account);
this.$store.commit(LOGIN_USER, data.account);
this.$snotify.success(this.$t('registration.success.login', { username: data.account.username }));
this.$router.push({ name: 'Home' });
}).catch((err) => {

View File

@@ -120,8 +120,8 @@
// });
// });
this.event.category_id = this.event.category;
this.event.organizer_actor_id = this.$store.state.user.actor.id;
this.event.participants = [this.$store.state.user.actor.id];
this.event.organizer_actor_id = this.$store.state.actor.id;
this.event.participants = [this.$store.state.actor.id];
// this.event.price = parseFloat(this.event.price);
if (this.id === undefined) {

View File

@@ -16,7 +16,7 @@
<v-icon>chevron_left</v-icon>
</v-btn>
<v-spacer></v-spacer>
<v-btn icon class="mr-3 white--text" v-if="event.organizer.id === $store.state.user.actor.id" :to="{ name: 'EditEvent', params: {id: event.id}}">
<v-btn icon class="mr-3 white--text" v-if="actorIsOrganizer()" :to="{ name: 'EditEvent', params: {id: event.id}}">
<v-icon>edit</v-icon>
</v-btn>
<v-menu bottom left>
@@ -27,7 +27,7 @@
<v-list-tile @click="downloadIcsEvent()">
<v-list-tile-title>Download</v-list-tile-title>
</v-list-tile>
<v-list-tile @click="deleteEvent()" v-if="$store.state.user.actor.id === event.organizer.id">
<v-list-tile @click="deleteEvent()" v-if="actorIsOrganizer()">
<v-list-tile-title>Delete</v-list-tile-title>
</v-list-tile>
</v-list>
@@ -217,10 +217,10 @@
})
},
actorIsParticipant() {
return this.event.participants.map(participant => participant.id).includes(this.$store.state.user.actor.id) || this.actorIsOrganizer();
return this.$store.state.actor && this.event.participants.map(participant => participant.id).includes(this.$store.state.actor.id) || this.actorIsOrganizer();
},
actorIsOrganizer() {
return this.$store.state.user.actor.id === this.event.organizer.id;
return this.$store.state.actor && this.$store.state.actor.id === this.event.organizer.id;
}
},
props: {

View File

@@ -11,7 +11,7 @@
<v-icon>chevron_left</v-icon>
</v-btn>
<v-spacer></v-spacer>
<!--<v-btn icon class="mr-3" v-if="$store.state.user && $store.state.user.actor.id === actor.id">-->
<!--<v-btn icon class="mr-3" v-if="$store.state.user && $store.state.actor.id === actor.id">-->
<!--<v-icon>edit</v-icon>-->
<!--</v-btn>-->
<v-btn icon>

View File

@@ -16,11 +16,11 @@
</v-layout>
</v-container>
</v-jumbotron>
<v-layout>
<v-layout v-else>
<v-flex xs12 sm8 offset-sm2>
<v-layout row wrap>
<v-flex xs12 sm6>
<h1>Welcome back {{ $store.state.user.actor.username }}</h1>
<h1>Welcome back {{ $store.state.actor.username }}</h1>
</v-flex>
<v-flex xs12 sm6>
<v-layout align-center>
@@ -51,7 +51,7 @@
</v-card-media>
<v-card-title primary-title>
<div>
<span class="grey--text">{{ event.begins_on | formatDate }}</span><br>
<span class="grey--text">{{ event.begins_on | formatDay }}</span><br>
<router-link :to="{name: 'Account', params: { name: event.organizer.username } }">
<v-avatar size="25px">
<img class="img-circle elevation-7 mb-1"
@@ -100,8 +100,8 @@ export default {
this.fetchData();
},
computed: {
displayed_name: function() {
return this.$store.state.user.actor.display_name === null ? this.$store.state.user.actor.username : this.$store.state.user.actor.display_name
displayed_name() {
return this.$store.state.actor.display_name === null ? this.$store.state.actor.username : this.$store.state.actor.display_name
},
},
methods: {

View File

@@ -75,8 +75,7 @@
</v-card-actions>
</v-card>
</v-menu>
<v-btn flat @click="$router.push({name: 'Account', params: { name: getUser().actor.username }})" v-if="$store.state.user">{{ this.displayed_name }}</v-btn>
<v-btn v-else :to="{ name: 'Login' }">Se connecter</v-btn>
<v-btn v-if="!$store.state.user" :to="{ name: 'Login' }">Se connecter</v-btn>
</v-toolbar>
</template>
@@ -123,7 +122,10 @@
},
computed: {
displayed_name: function() {
return this.$store.state.user.actor.display_name === null ? this.$store.state.user.actor.username : this.$store.state.user.actor.display_name
console.log('displayed name', this.$store.state.actor);
if (this.$store.state.actor) {
return this.$store.state.actor.display_name === null ? this.$store.state.actor.username : this.$store.state.actor.display_name;
}
},
},
methods: {

View File

@@ -3,36 +3,21 @@
import Vue from 'vue';
// import * as VueGoogleMaps from 'vue2-google-maps';
import VueMarkdown from 'vue-markdown';
import VuetifyGoogleAutocomplete from 'vuetify-google-autocomplete';
import Vuetify from 'vuetify';
import Vuex from 'vuex';
import moment from 'moment';
import VuexI18n from 'vuex-i18n';
import 'material-design-icons/iconfont/material-icons.css';
import 'vuetify/dist/vuetify.min.css';
import App from '@/App';
import router from '@/router';
import storeData from '@/store/index';
import translations from '@/i18n/index';
import auth from '@/auth';
import App from './App.vue';
import router from './router';
import store from './store';
import translations from './i18n';
import auth from './auth';
Vue.config.productionTip = false;
Vue.use(VuetifyGoogleAutocomplete, {
apiKey: 'AIzaSyBF37pw38j0giICt73TCAPNogc07Upe_Q4', // Can also be an object. E.g, for Google Maps Premium API, pass `{ client: <YOUR-CLIENT-ID> }`
});
/*Vue.use(VueGoogleMaps, {
load: {
key: 'AIzaSyBF37pw38j0giICt73TCAPNogc07Upe_Q4',
libraries: 'places',
installComponents: false,
},
});*/
Vue.use(VueMarkdown);
Vue.use(Vuetify);
Vue.use(Vuex);
let language = window.navigator.userLanguage || window.navigator.language;
moment.locale(language);
@@ -43,8 +28,6 @@ if (!(language in translations)) {
[language] = language.split('-', 1);
}
const store = new Vuex.Store(storeData);
Vue.use(VuexI18n.plugin, store);
Object.entries(translations).forEach((key) => {
@@ -55,17 +38,21 @@ Vue.i18n.set(language);
Vue.i18n.fallback('en');
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiredAuth) && store.state.user === undefined || store.state.user == null) {
if (to.matched.some(record => record.meta.requiredAuth)) {
next({
name: 'Login',
query: { redirect: to.fullPath }
query: { redirect: to.fullPath },
});
} else {
next();
}
});
auth.getUser(store, () => {}, () => {});
auth.getUser(store, () => {}, (error) => {
console.warn(error);
});
console.log('store', store);
/* eslint-disable no-new */
new Vue({

View File

@@ -1,8 +1,12 @@
import { LOGIN_USER, LOGOUT_USER, LOAD_USER } from './mutation-types';
import Vue from 'vue';
import Vuex from 'vuex';
import { LOGIN_USER, LOGOUT_USER, LOAD_USER, CHANGE_ACTOR } from './mutation-types';
const state = {
isLogged: !!localStorage.getItem('token'),
user: false,
actor: false,
defaultActor: localStorage.getItem('defaultActor') || null,
};
/* eslint-disable */
@@ -20,7 +24,21 @@ const mutations = {
state.isLogged = false;
state.user = null;
},
[CHANGE_ACTOR](state, actor) {
state.actor = actor;
state.defaultActor = actor.username;
}
};
/* eslint-enable */
export default { state, mutations };
Vue.use(Vuex);
const store = new Vuex.Store({ state, mutations });
store.subscribe((mutation, localState) => {
if (mutation === CHANGE_ACTOR) {
localStorage.setItem('defaultActor', localState.actor.username);
}
});
export default store;

View File

@@ -1,3 +1,4 @@
export const LOGIN_USER = 'LOGIN_USER';
export const LOAD_USER = 'LOAD_USER';
export const LOGOUT_USER = 'LOGOUT_USER';
export const CHANGE_ACTOR = 'CHANGE_ACTOR';