186 lines
5.2 KiB
JavaScript
186 lines
5.2 KiB
JavaScript
import '@babel/polyfill';
|
|
import Vue from 'vue';
|
|
import axios from 'axios';
|
|
import VueAxios from 'vue-axios';
|
|
import VueVimeoPlayer from 'vue-vimeo-player';
|
|
import apolloClientFactory from './graphql/client';
|
|
import VueApollo from 'vue-apollo';
|
|
import App from './App';
|
|
import router from './router';
|
|
import store from '@/store/index';
|
|
import VueScrollTo from 'vue-scrollto';
|
|
import {Validator, install as VeeValidate} from 'vee-validate/dist/vee-validate.minimal.esm.js';
|
|
import {required, min, decimal, confirmed} from 'vee-validate/dist/rules.esm.js';
|
|
import veeDe from 'vee-validate/dist/locale/de';
|
|
import {dateFilter} from './filters/date-filter';
|
|
import autoGrow from '@/directives/auto-grow';
|
|
import clickOutside from '@/directives/click-outside';
|
|
import ME_QUERY from '@/graphql/gql/meQuery.gql';
|
|
import VueModal from '@/plugins/modal';
|
|
import VueRemoveEdges from '@/plugins/edges';
|
|
import VueMatomo from 'vue-matomo';
|
|
import VueToast from 'vue-toast-notification';
|
|
Vue.config.productionTip = false;
|
|
|
|
Vue.use(VueModal);
|
|
Vue.use(VueRemoveEdges);
|
|
Vue.use(VueApollo);
|
|
Vue.use(VueAxios, axios);
|
|
Vue.use(VueVimeoPlayer);
|
|
Vue.use(VueToast);
|
|
|
|
Vue.use(VueScrollTo, {
|
|
duration: 500,
|
|
easing: 'ease-out',
|
|
offset: -50
|
|
});
|
|
|
|
if (process.env.MATOMO_HOST) {
|
|
Vue.use(VueMatomo, {
|
|
host: process.env.MATOMO_HOST,
|
|
siteId: process.env.MATOMO_SITE_ID,
|
|
router: router
|
|
});
|
|
}
|
|
|
|
Vue.directive('click-outside', clickOutside);
|
|
Vue.directive('auto-grow', autoGrow);
|
|
|
|
const publicApolloClient = apolloClientFactory('/api/graphql-public/', null);
|
|
const privateApolloClient = apolloClientFactory('/api/graphql/', networkErrorCallback);
|
|
|
|
const apolloProvider = new VueApollo({
|
|
clients: {
|
|
publicClient: publicApolloClient
|
|
},
|
|
defaultClient: privateApolloClient
|
|
});
|
|
|
|
Validator.extend('required', required);
|
|
Validator.extend('min', min);
|
|
Validator.extend('decimal', decimal);
|
|
Validator.extend('confirmed', confirmed);
|
|
|
|
const dict = {
|
|
custom: {
|
|
oldPassword: {
|
|
required: 'Dein aktuelles Passwort fehlt'
|
|
},
|
|
newPassword: {
|
|
required: 'Dein neues Passwort fehlt',
|
|
min: 'Das neue Passwort muss mindestens 8 Zeichen lang sein'
|
|
}
|
|
}
|
|
};
|
|
|
|
Validator.localize('de', veeDe);
|
|
Validator.localize('de', dict);
|
|
|
|
// https://github.com/baianat/vee-validate/issues/51
|
|
Validator.extend('strongPassword', {
|
|
getMessage: field => 'Das Passwort muss Grossbuchstaben, Zahlen und Sonderzeichen beinhalten und mindestens 8 Zeichen lang sein',
|
|
validate: value => {
|
|
const strongRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*?(),.":{}|<>+])(?=.{8,})/;
|
|
return strongRegex.test(value);
|
|
}
|
|
});
|
|
|
|
Validator.extend('email', {
|
|
getMessage: field => 'Bitte geben Sie eine gülitge E-Mail an',
|
|
validate: value => {
|
|
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
|
|
return emailRegex.test(value);
|
|
}
|
|
});
|
|
|
|
Vue.use(VeeValidate, {
|
|
locale: 'de'
|
|
});
|
|
|
|
Vue.filter('date', dateFilter);
|
|
|
|
/* guards */
|
|
|
|
function getCookieValue(cookieName) {
|
|
// https://stackoverflow.com/questions/5639346/what-is-the-shortest-function-for-reading-a-cookie-by-name-in-javascript
|
|
let cookieValue = document.cookie.match('(^|[^;]+)\\s*' + cookieName + '\\s*=\\s*([^;]+)');
|
|
return cookieValue ? cookieValue.pop() : '';
|
|
}
|
|
|
|
function loginRequired(to) {
|
|
// public pages have the meta.public property set to true
|
|
return !to.hasOwnProperty('meta') || !to.meta.hasOwnProperty('public') || !to.meta.public;
|
|
}
|
|
|
|
function unauthorizedAccess(to) {
|
|
return loginRequired(to) && getCookieValue('loginStatus') !== 'true';
|
|
}
|
|
|
|
function redirectUsersWithoutValidLicense(to) {
|
|
return privateApolloClient.query({
|
|
query: ME_QUERY,
|
|
}).then(({data}) => data.me.expiryDate == null);
|
|
}
|
|
|
|
function redirectStudentsWithoutClass() {
|
|
return privateApolloClient.query({
|
|
query: ME_QUERY,
|
|
}).then(({data}) => data.me.schoolClasses.edges.length === 0 && data.me.permissions.length === 0);
|
|
}
|
|
|
|
function redirectUsersToOnboarding(to) {
|
|
return privateApolloClient.query({
|
|
query: ME_QUERY,
|
|
}).then(({data}) => !data.me.onboardingVisited);
|
|
}
|
|
|
|
function networkErrorCallback(statusCode) {
|
|
if (statusCode === 402) {
|
|
router.push({name: 'licenseActivation'}, 0);
|
|
}
|
|
}
|
|
|
|
function joiningClass(to) {
|
|
return to.name && (to.name === 'join-class' || to.name === 'licenseActivation');
|
|
}
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
if (to.path === '/logout') {
|
|
publicApolloClient.resetStore();
|
|
next({name: 'hello'});
|
|
return;
|
|
}
|
|
|
|
if (unauthorizedAccess(to)) {
|
|
const redirectUrl = `/hello?redirect=${to.path}`;
|
|
next(redirectUrl);
|
|
return;
|
|
}
|
|
|
|
if (to.name && to.name !== 'licenseActivation' && loginRequired(to) && await redirectUsersWithoutValidLicense()) {
|
|
next({name: 'licenseActivation'});
|
|
return;
|
|
}
|
|
|
|
if (!joiningClass(to) && loginRequired(to) && await redirectStudentsWithoutClass()) {
|
|
next({name: 'join-class'});
|
|
return;
|
|
}
|
|
|
|
if ((to.name && to.name.indexOf('onboarding') === -1) && !joiningClass(to) && loginRequired(to) && await redirectUsersToOnboarding()) {
|
|
next({name: 'onboarding-start'});
|
|
return;
|
|
}
|
|
|
|
next();
|
|
});
|
|
|
|
/* eslint-disable no-new */
|
|
new Vue({
|
|
el: '#app',
|
|
store,
|
|
router,
|
|
provide: apolloProvider.provide(),
|
|
render: h => h(App)
|
|
});
|