added user repo and group management working now

This commit is contained in:
2019-04-11 16:18:18 +02:00
parent 654c78ff7c
commit 98f5d3f39b
11 changed files with 236 additions and 97 deletions

13
package-lock.json generated
View File

@@ -11914,6 +11914,11 @@
"util.promisify": "~1.0.0" "util.promisify": "~1.0.0"
} }
}, },
"sweetalert2": {
"version": "7.33.1",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-7.33.1.tgz",
"integrity": "sha512-69KYtyhtxejFG0HDb8aVhAwbpAWPSTZwaL5vxDHgojErD2KeFxTmRgmkbiLtMC8UdTFXRmvTPtZTF4459MUb7w=="
},
"symbol-observable": { "symbol-observable": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
@@ -12972,6 +12977,14 @@
"loader-utils": "^1.0.2" "loader-utils": "^1.0.2"
} }
}, },
"vue-sweetalert2": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/vue-sweetalert2/-/vue-sweetalert2-1.6.4.tgz",
"integrity": "sha512-MsVPeie+DjyP/rTPHlGxOsnR10DCXq/6xUiMZtBURZq8111Q/U6c8xJ0do55Yj99odf7ru2J2eJz6GeGs8i0kA==",
"requires": {
"sweetalert2": "7.x"
}
},
"vue-template-compiler": { "vue-template-compiler": {
"version": "2.6.8", "version": "2.6.8",
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.8.tgz", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.8.tgz",

View File

@@ -24,7 +24,8 @@
"vue-i18n": "^8.9.0", "vue-i18n": "^8.9.0",
"vue-property-decorator": "^7.0.0", "vue-property-decorator": "^7.0.0",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vuejs-logger": "1.5.3", "vue-sweetalert2": "^1.6.4",
"vuejs-logger": "^1.5.3",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-persistedstate": "^2.5.4", "vuex-persistedstate": "^2.5.4",
"vuex-typex": "^3.1.4" "vuex-typex": "^3.1.4"

View File

@@ -7,6 +7,33 @@ import store from "@/store";
const baseDomain = "http://localhost:5443"; const baseDomain = "http://localhost:5443";
const API_URL = `${baseDomain}/api/v1`; const API_URL = `${baseDomain}/api/v1`;
export default axios.create({ const api = axios.create({
baseURL: API_URL, headers: { Authorization: `Bearer ${store.state.access_token}` }, baseURL: API_URL, headers: { Authorization: `Bearer ${store.state.access_token}` },
}); });
api.interceptors.response.use(function (response) {
return response;
}, function (error) {
if (401 === error.response.status) {
Vue.swal({
title: "Session Expired",
text: "Your token/session has expired. Would you like to be redirected to the login page?",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#DD6B55",
confirmButtonText: "Yes",
}).then( (result) => {
if(result.value) {
console.log("redirect to login!");
window.location = '/login';
} else {
console.log("redirect to home!");
window.location = '/';
}
});
} else {
return Promise.reject(error);
}
});
export default api;

View File

@@ -1,9 +1,11 @@
// RepositoryFactory.js // RepositoryFactory.js
import GroupRepository from "./groupRepository"; import GroupRepository from "./groupRepository";
import UserRepository from "./userRepository";
const repositories = { const repositories = {
group: GroupRepository, group: GroupRepository,
user: UserRepository,
}; };
export const RepositoryFactory = { export const RepositoryFactory = {

View File

@@ -5,7 +5,7 @@ import Repository from "./Repository";
const resource = "/group"; const resource = "/group";
export default { export default {
get() { getGroups() {
return Repository.get(`${resource}`); return Repository.get(`${resource}`);
}, },

View File

@@ -49,6 +49,14 @@ export function createUser(jwt: any, userData: any) {
return axios.post(`${API_URL}/v1/user`, userData, { headers: { Authorization: `Bearer ${jwt}` } }); return axios.post(`${API_URL}/v1/user`, userData, { headers: { Authorization: `Bearer ${jwt}` } });
} }
export function fetchUserGroups(jwt: any) {
return axios.get(`${API_URL}/v1/group`, { headers: { Authorization: `Bearer ${jwt}` } });
}
export function fetchUserGroup(jwt: any, groupId: any) {
return axios.get(`${API_URL}/v1/group/${groupId}`, { headers: { Authorization: `Bearer ${jwt}` } });
}
export function fetchProfile(jwt: any) { export function fetchProfile(jwt: any) {
Vue.$log.debug("JWT: "+ jwt); Vue.$log.debug("JWT: "+ jwt);
return axios.get(`${API_URL}/v1/user/profile`, { headers: { Authorization: `Bearer ${jwt}` } }); return axios.get(`${API_URL}/v1/user/profile`, { headers: { Authorization: `Bearer ${jwt}` } });

19
src/api/userRepository.js Normal file
View File

@@ -0,0 +1,19 @@
// groupRepository.js
import Repository from "./Repository";
const resource = "/user";
export default {
getUsers() {
return Repository.get(`${resource}`);
},
getUser(userId) {
return Repository.get(`${resource}/${userId}`);
},
createUser(userData) {
return Repository.post(`${resource}`, userData);
},
};

View File

@@ -30,39 +30,18 @@
</div> </div>
</div> </div>
<div id="sixthTable">
<table>
<thead>
<tr>
<th v-for="col in columns" v-on:click="sortTable(col)">{{col}}
<div class="arrow" v-if="col == sortColumn" v-bind:class="[ascending ? 'arrow_up' : 'arrow_down']"></div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in get_rows()">
<td v-for="col in columns">{{row[col]}}</td>
</tr>
</tbody>
</table>
<div class="pagination">
<div class="number"
v-for="i in num_pages()"
v-bind:class="[i == currentPage ? 'active' : '']"
v-on:click="change_page(i)">{{i}}</div>
</div>
</div>
<p class="subtitle error-msg">{{ errorMsg }}</p> <p class="subtitle error-msg">{{ errorMsg }}</p>
<h3 class="title">Add Group</h3> <h3 class="title">Add Group</h3>
<label>
<input v-model="group.name" placeholder="Group name"> <input v-model="group.name" placeholder="Group name">
</label>
<p>Name is: {{ group.name }}</p> <p>Name is: {{ group.name }}</p>
<span>Multiline message is:</span> <span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ group.description }}</p> <p style="white-space: pre-line;">{{ group.description }}</p>
<br> <br>
<textarea v-model="group.message" placeholder="Description for group"></textarea> <textarea v-model="group.description" placeholder="Description for group"></textarea>
<button v-on:click="create_group">{{$t('create_group')}}</button> <button v-on:click="createGroup">{{$t('create_group')}}</button>
</div> </div>
</div> </div>
</section> </section>
@@ -79,28 +58,19 @@
data () { data () {
return { return {
isLoading: false, isLoading: false,
errorMsg: '',
groups: [], groups: [],
group: {}, errorMsg: '',
currentPage: 1, group: {name:'', description:''},
elementsPerPage: 3,
ascending: false,
sortColumn: '', sortColumn: '',
rows: [ currentPage: 1,
{ id: 1, name: "Chandler Bing", phone: '305-917-1301', profession: 'IT Manager' }, elementsPerPage: 5,
{ id: 2, name: "Ross Geller", phone: '210-684-8953', profession: 'Paleontologist' },
{ id: 3, name: "Rachel Green", phone: '765-338-0312', profession: 'Waitress'},
{ id: 4, name: "Monica Geller", phone: '714-541-3336', profession: 'Head Chef' },
{ id: 5, name: "Joey Tribbiani", phone: '972-297-6037', profession: 'Actor' },
{ id: 6, name: "Phoebe Buffay", phone: '760-318-8376', profession: 'Masseuse' }
],
}; };
}, },
methods: { methods: {
fetch() { fetch() {
this.isLoading = true; this.isLoading = true;
// const { data } = await GroupRepository.get(); // const { data } = await GroupRepository.get();
GroupRepository.get() GroupRepository.getGroups()
.then(response => { .then(response => {
this.groups = response.data; this.groups = response.data;
this.isLoading = false; this.isLoading = false;
@@ -108,6 +78,17 @@
}); });
}, },
get_group_rows() {
var start = (this.currentPage-1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.groups.slice(start, end);
},
num_group_pages() {
return Math.ceil(this.groups.length / this.elementsPerPage);
},
change_page(page) {
this.currentPage = page;
},
sortTable(col) { sortTable(col) {
if (this.sortColumn === col) { if (this.sortColumn === col) {
this.ascending = !this.ascending; this.ascending = !this.ascending;
@@ -118,7 +99,7 @@
var ascending = this.ascending; var ascending = this.ascending;
this.rows.sort(function(a, b) { this.groups.sort(function(a, b) {
if (a[col] > b[col]) { if (a[col] > b[col]) {
return ascending ? 1 : -1 return ascending ? 1 : -1
} else if (a[col] < b[col]) { } else if (a[col] < b[col]) {
@@ -127,44 +108,24 @@
return 0; return 0;
}) })
}, },
num_pages() { createGroup(){
return Math.ceil(this.rows.length / this.elementsPerPage); this.$log.info("Creating new group...");
GroupRepository.createGroup(this.group);
this.fetch();
}, },
num_group_pages() {
return Math.ceil(this.groups.length / this.elementsPerPage);
},
get_rows() {
var start = (this.currentPage-1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.rows.slice(start, end);
},
get_group_rows() {
var start = (this.currentPage-1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.groups.slice(start, end);
},
change_page(page) {
this.currentPage = page;
},
}, },
mounted() { mounted() {
this.fetch(); this.fetch();
}, },
computed: { beforeDestroy() {
columns() {
if (this.rows.length === 0) {
return [];
}
return Object.keys(this.rows[0])
}, },
computed: {
group_columns() { group_columns() {
if (this.groups.length === 0) { if (this.groups.length === 0) {
return []; return [];
} }
return Object.keys(this.groups[0]) return Object.keys(this.groups[0]);
} },
}, },
} }
</script> </script>

View File

@@ -5,6 +5,38 @@
<div class="hero-body"> <div class="hero-body">
<div class="container has-text-centered"> <div class="container has-text-centered">
<h3 class="title">Manage users</h3> <h3 class="title">Manage users</h3>
<div>{{users}}</div>
<div id="userTable">
<table>
<thead>
<tr>
<th v-for="col in columns" v-on:click="sortTable(col)">{{col}}
<div class="arrow" v-if="col == sortColumn" v-bind:class="[ascending ? 'arrow_up' : 'arrow_down']"></div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in get_rows()">
<td v-for="col in columns">{{row[col]}}</td>
</tr>
</tbody>
</table>
<div class="pagination">
<div class="number"
v-for="i in num_pages()"
v-bind:class="[i === currentPage ? 'active' : '']"
v-on:click="change_page(i)">{{i}}</div>
</div>
</div>
<h3 class="title">Add User</h3>
<label>
<input v-model="user.first_name" placeholder="First name">
</label>
<p>Name is: {{ user.first_name }}</p>
<button v-on:click="createUser">{{$t('create_user')}}</button>
<p class="subtitle error-msg">{{ errorMsg }}</p> <p class="subtitle error-msg">{{ errorMsg }}</p>
</div> </div>
@@ -17,24 +49,80 @@
<script> <script>
import { EventBus } from '@/utils' import { EventBus } from '@/utils'
import {getRemainingJwtValiditySeconds} from "../utils"; import {getRemainingJwtValiditySeconds} from "../utils";
import { RepositoryFactory} from "@/api/RepositoryFactory";
const UserRepository = RepositoryFactory.get('user');
export default { export default {
data() { data() {
return { return {
users: '', user: {},
users: [],
errorMsg: '', errorMsg: '',
sortColumn: '',
currentPage: 1,
elementsPerPage: 5
}; };
}, },
methods: { methods: {
fetch() {
this.isLoading = true;
// const { data } = await GroupRepository.get();
UserRepository.getUsers()
.then(response => {
this.users = response.data;
this.isLoading = false;
this.$log.debug(response);
});
}, },
mounted () { get_rows() {
var start = (this.currentPage-1) * this.elementsPerPage;
var end = start + this.elementsPerPage;
return this.users.slice(start, end);
},
num_pages() {
return Math.ceil(this.users.length / this.elementsPerPage);
},
change_page(page) {
this.currentPage = page;
},
sortTable(col) {
if (this.sortColumn === col) {
this.ascending = !this.ascending;
} else {
this.ascending = true;
this.sortColumn = col;
}
var ascending = this.ascending;
this.users.sort(function(a, b) {
if (a[col] > b[col]) {
return ascending ? 1 : -1
} else if (a[col] < b[col]) {
return ascending ? -1 : 1
}
return 0;
})
},
createUser(){
this.$log.info("Creating new user...");
UserRepository.createUser(this.user);
this.fetch();
},
},
mounted() {
this.fetch();
}, },
beforeDestroy() { beforeDestroy() {
}, },
computed: { computed: {
columns() {
if (this.users.length === 0) {
return [];
}
return Object.keys(this.users[0]);
},
}, },
} }
</script> </script>

View File

@@ -4,6 +4,7 @@ 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';
import VueSweetalert2 from 'vue-sweetalert2';
import VueCookies from 'vue-cookies'; import VueCookies from 'vue-cookies';
import VueLogger from 'vuejs-logger'; import VueLogger from 'vuejs-logger';
import i18n from '@/plugins/i18n'; import i18n from '@/plugins/i18n';
@@ -32,6 +33,7 @@ Vue.use(VueLogger, options);
Vue.use(VueAxios, axios); Vue.use(VueAxios, axios);
Vue.use(FlagIcon); Vue.use(FlagIcon);
Vue.use(VueCookies); Vue.use(VueCookies);
Vue.use(VueSweetalert2);
// setup fake backend // setup fake backend
// import { configureFakeBackend } from './helpers'; // import { configureFakeBackend } from './helpers';

View File

@@ -11,9 +11,10 @@ import {
postNewSurvey, postNewSurvey,
authenticate, authenticate,
register, register,
oidc_login, fetchUsers, getFreshToken, fetchProfile, oidc_login, fetchUsers, getFreshToken, fetchProfile, fetchUserGroups,
} from '@/api'; } from '@/api';
import {isValidJwt, EventBus} from '@/utils'; import {isValidJwt, EventBus} from '@/utils';
import {response} from "express";
Vue.use(Vuex); Vue.use(Vuex);
@@ -24,6 +25,7 @@ const state = {
currentSurvey: {}, currentSurvey: {},
profile: {}, profile: {},
users: [], users: [],
userGroups: [],
access_token: '', access_token: '',
refresh_token: '', refresh_token: '',
}; };
@@ -59,6 +61,19 @@ const actions = {
EventBus.$emit('failedLoadingUsers', error); EventBus.$emit('failedLoadingUsers', error);
}); });
}, },
loadUserGroups(context: any) {
return fetchUserGroups(context.state.access_token)
.then((response) => {
Vue.$log.debug(response);
Vue.$log.debug(response.data);
context.commit('setUserGroups', { groups: response.data });
EventBus.$emit('groupsLoaded', response.data);
})
.catch((error) => {
Vue.$log.warn('Error loading user groups!', error);
EventBus.$emit('failedLoadingUserGroups', error);
});
},
loadProfileAuthCheck(context:any){ loadProfileAuthCheck(context:any){
if (!getters.isAuthenticated) { if (!getters.isAuthenticated) {
EventBus.$emit('accessTokenInvalid'); EventBus.$emit('accessTokenInvalid');
@@ -158,6 +173,9 @@ const mutations = {
setUsers(sState: any, payload: any) { setUsers(sState: any, payload: any) {
sState.users = payload.users; sState.users = payload.users;
}, },
setUserGroups(sState: any, payload: any) {
sState.userGroups = payload.groups;
},
setChoice(sState: any, payload: any) { setChoice(sState: any, payload: any) {
const { questionId, choice } = payload; const { questionId, choice } = payload;
const nQuestions = sState.currentSurvey.questions.length; const nQuestions = sState.currentSurvey.questions.length;