Better handle focus perks

This commit is contained in:
Pavle Portic 2019-03-26 15:27:00 +01:00
parent 87b4a25aa6
commit 747478f0d7
Signed by: TheEdgeOfRage
GPG Key ID: 6758ACE46AA2A849
17 changed files with 132 additions and 59 deletions

6
backend/Pipfile.lock generated
View File

@ -50,11 +50,11 @@
}, },
"markdown": { "markdown": {
"hashes": [ "hashes": [
"sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa", "sha256:fc4a6f69a656b8d858d7503bda633f4dd63c2d70cf80abdc6eafa64c4ae8c250",
"sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c" "sha256:fe463ff51e679377e3624984c829022e2cfb3be5518726b06f608a07a3aad680"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.0.1" "version": "==3.1"
}, },
"psycopg2-binary": { "psycopg2-binary": {
"hashes": [ "hashes": [

View File

@ -1,7 +1,8 @@
from django.contrib import admin from django.contrib import admin
from .models import Tree, Perk from .models import Tree, Perk, User
admin.site.register(Tree) admin.site.register(Tree)
admin.site.register(Perk) admin.site.register(Perk)
admin.site.register(User)

View File

@ -16,6 +16,9 @@ class Tree(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
def __repr__(self):
return f'<Tree: {str(self)}>'
class Meta: class Meta:
ordering = ('name',) ordering = ('name',)
@ -29,7 +32,10 @@ class Perk(models.Model):
trees = models.ManyToManyField('Tree', related_name='perks', symmetrical=False) trees = models.ManyToManyField('Tree', related_name='perks', symmetrical=False)
def __str__(self): def __str__(self):
return f'{self.name}' return f'{self.name} [{self.level}]'
def __repr__(self):
return f'<Perk: {str(self)}>'
class Meta: class Meta:
ordering = ('name',) ordering = ('name',)
@ -39,3 +45,9 @@ class User(models.Model):
base_user = models.OneToOneField(AuthUser, on_delete=models.CASCADE) base_user = models.OneToOneField(AuthUser, on_delete=models.CASCADE)
perks = models.ManyToManyField(Perk, related_name='users', symmetrical=False) perks = models.ManyToManyField(Perk, related_name='users', symmetrical=False)
def __str__(self):
return f'{self.base_user.username} ({self.id})'
def __repr__(self):
return f'<User: {str(self)}>'

View File

@ -8,6 +8,7 @@
import csv import csv
import re import re
from .models import Tree, Perk from .models import Tree, Perk
requirement_pattern = re.compile(r'([\w\s]+) \(([\w\s]+)\)') requirement_pattern = re.compile(r'([\w\s]+) \(([\w\s]+)\)')
@ -94,11 +95,19 @@ class PerkParser():
elif 'Skill Focus' in req_name or 'Ability Focus' in req_name: elif 'Skill Focus' in req_name or 'Ability Focus' in req_name:
req_match = re.match(requirement_pattern, req_name) req_match = re.match(requirement_pattern, req_name)
req_tree = Tree.objects.get(name=req_match.group(2)) req_tree = Tree.objects.get(name=req_match.group(2))
req_base_name = req_match.group(1) req_base_name = req_match.group(1)
base_req = Perk.objects.get(name=req_base_name) base_req = Perk.objects.get(name=req_base_name)
req = self.create_perk(name=req_name, effect=base_req.effect, level=base_req.level, perk_type=base_req.type, trees=[req_tree]) req = self.create_perk(name=req_name, effect=base_req.effect, level=base_req.level, perk_type=base_req.type, trees=[req_tree])
if 'Greater' in req_base_name:
greater_req_name = req_name[8:]
try:
greater_req = Perk.objects.get(name=greater_req_name)
except Perk.DoesNotExist:
greater_req_base_name = req_base_name[8:]
greater_base_req = Perk.objects.get(name=greater_req_base_name)
greater_req = self.create_perk(name=greater_req_name, effect=greater_base_req.effect, level=greater_base_req.level, perk_type=greater_base_req.type, trees=[req_tree])
req.parents.add(greater_req)
else: else:
req = self.create_perk(name=req_name, level=0, perk_type=4) req = self.create_perk(name=req_name, level=0, perk_type=4)
perk.parents.add(req) perk.parents.add(req)

View File

@ -23,10 +23,6 @@ export default class AuthApi {
return Axios.post(ENDPOINTS.LOGIN, data); return Axios.post(ENDPOINTS.LOGIN, data);
} }
static signup(data) {
return Axios.post(ENDPOINTS.USER, data);
}
static changePassword(data) { static changePassword(data) {
return Axios.patch(ENDPOINTS.USER, data); return Axios.patch(ENDPOINTS.USER, data);
} }

View File

@ -16,6 +16,10 @@ export default class AuthApi {
return Axios.get(ENDPOINTS.USER); return Axios.get(ENDPOINTS.USER);
} }
static createUser(data) {
return Axios.post(ENDPOINTS.USER, data);
}
static updatePerks(data) { static updatePerks(data) {
return Axios.patch(ENDPOINTS.USER, data); return Axios.patch(ENDPOINTS.USER, data);
} }

View File

@ -44,7 +44,10 @@ export default {
{ icon: 'fas fa-code-branch', text: 'Perk trees', to: { name: 'trees' } }, { icon: 'fas fa-code-branch', text: 'Perk trees', to: { name: 'trees' } },
{ icon: 'fas fa-sign-out-alt', text: 'Logout', to: { name: 'logout' } }, { icon: 'fas fa-sign-out-alt', text: 'Logout', to: { name: 'logout' } },
], ],
false: [{ icon: 'fas fa-sign-in-alt', text: 'Login', to: { name: 'login' } }], false: [
{ icon: 'fas fa-sign-in-alt', text: 'Login', to: { name: 'login' } },
{ icon: 'fas fa-user-plus ', text: 'Sign up', to: { name: 'signup' } },
],
}, },
}; };
}, },

View File

@ -68,7 +68,7 @@
email: this.email, email: this.email,
password: this.password, password: this.password,
}; };
AuthController.register(data).then(() => { AuthController.signup(data).then(() => {
this.$router.push({ name: 'index' }); this.$router.push({ name: 'index' });
}).catch((error) => { }).catch((error) => {
if (error.response) { if (error.response) {
@ -83,8 +83,9 @@
<style lang="stylus"> <style lang="stylus">
.signup-form-card .signup-form-card
padding 2rem padding 2rem
margin-top 5rem
.login-errors .signup-errors
color red color red
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<v-container class="perktree"> <v-container class="perktree">
<v-layout row wrap> <v-layout row wrap>
<v-flex xl8 offset-xl2 sm12> <v-flex xl10 offset-xl1 sm12>
<v-card> <v-card>
<div id="perktree"></div> <div id="perktree"></div>
</v-card> </v-card>
@ -129,10 +129,8 @@ export default {
const clickedNode = _.find(nodes, (n) => { const clickedNode = _.find(nodes, (n) => {
return n.name === node.name; return n.name === node.name;
}); });
if (clickedNode.effect) { this.selectedPerk = clickedNode;
this.selectedPerk = clickedNode; this.dialog = true;
this.dialog = true;
}
}) })
.draw(graphData); .draw(graphData);
}, },

View File

@ -5,6 +5,8 @@
* Distributed under terms of the BSD-3-Clause license. * Distributed under terms of the BSD-3-Clause license.
*/ */
import * as _ from 'lodash';
import AuthApi from '../apis/auth.api'; import AuthApi from '../apis/auth.api';
import router from '../router'; import router from '../router';
import store from '../store'; import store from '../store';
@ -38,24 +40,22 @@ export default class AuthController {
} }
static setupToken() { static setupToken() {
const access = this.getLocalStorageToken().access; const access = AuthController.getLocalStorageToken().access;
AuthApi.setAuthHeader(access); if (access) {
store.commit('login'); AuthApi.setAuthHeader(access);
store.commit('login');
}
} }
static login(data) { static login(data) {
return AuthApi.login(data).then((response) => { return AuthApi.login(data).then((response) => {
this.setLocalStorageToken(response.data); AuthController.setLocalStorageToken(response.data);
this.setupToken(response.data); AuthController.setupToken(response.data);
}); });
} }
static signup(data) {
return AuthApi.signup(data);
}
static logout() { static logout() {
this.clearLocalStorageToken(); AuthController.clearLocalStorageToken();
store.commit('logout'); store.commit('logout');
AuthApi.setAuthHeader(''); AuthApi.setAuthHeader('');
} }
@ -65,7 +65,7 @@ export default class AuthController {
} }
static verifyToken() { static verifyToken() {
const token = this.getLocalStorageToken().access; const token = AuthController.getLocalStorageToken().access;
if (token === null) { if (token === null) {
router.push('login'); router.push('login');
} }
@ -73,22 +73,24 @@ export default class AuthController {
} }
static refreshToken() { static refreshToken() {
if (!this.getLocalStorageRefresh()) { if (!AuthController.getLocalStorageRefresh()) {
return Promise.reject(new Error('No token')); return Promise.reject(new Error('No token'));
} }
const refresh = { const refresh = {
refresh: this.getLocalStorageToken().refresh, refresh: AuthController.getLocalStorageToken().refresh,
}; };
_.delay(AuthController.refreshToken, 240000);
return AuthApi.refreshToken(refresh).then((response) => { return AuthApi.refreshToken(refresh).then((response) => {
this.setLocalStorageToken(response.data); AuthController.setLocalStorageToken(response.data);
this.setupToken(); AuthController.setupToken();
}); });
} }
static getAuthStatus() { static getAuthStatus() {
const token = this.getLocalStorageToken().access; const token = AuthController.getLocalStorageToken().access;
return Boolean(token); return Boolean(token);
} }
} }

View File

@ -12,6 +12,10 @@ export default class AuthController {
return UserApi.getUser(); return UserApi.getUser();
} }
static signup(data) {
return UserApi.signup(data);
}
static updatePerks(perks) { static updatePerks(perks) {
const data = { const data = {
perks, perks,

View File

@ -9,7 +9,7 @@ import './plugins/vuetify';
import App from './components/app.vue'; import App from './components/app.vue';
import { config } from './config'; import { config } from './config';
import router from './router'; import router from './router';
import store from './store'; import store from './store/';
import AuthController from './controllers/auth.controller'; import AuthController from './controllers/auth.controller';
import 'roboto-fontface/css/roboto/roboto-fontface.css'; import 'roboto-fontface/css/roboto/roboto-fontface.css';
@ -27,9 +27,7 @@ const configureHttp = () => {
}, },
(error) => { (error) => {
if (error.response && error.response.status === 401) { if (error.response && error.response.status === 401) {
AuthController.refreshToken().then(() => { AuthController.refreshToken().catch(() => {
router.push({ path: router.currentRoute.path });
}).catch(() => {
router.push({ router.push({
name: 'logout', name: 'logout',
}); });
@ -42,12 +40,10 @@ const configureHttp = () => {
}; };
const configureRaven = () => { const configureRaven = () => {
if (config.getEnv() !== 'dev') { Raven
Raven .config('https://2b1b0eea285244289175e53d65421fac@sentry.theedgeofrage.com/3')
.config('https://2b1b0eea285244289175e53d65421fac@sentry.theedgeofrage.com/3') .addPlugin(RavenVue, Vue)
.addPlugin(RavenVue, Vue) .install();
.install();
}
}; };
configureHttp(); configureHttp();

View File

@ -37,7 +37,7 @@ const router = new Router({
}, },
{ {
path: '/signup', path: '/signup',
name: 'signpu', name: 'signup',
component: Signup, component: Signup,
meta: { meta: {
guest: true, guest: true,

View File

@ -1,17 +1,12 @@
/* /*
* store.js * auth.js
* Copyright (C) 2019 pavle <pavle.portic@tilda.center> * Copyright (C) 2019 pavle <pavle.portic@tilda.center>
* *
* Distributed under terms of the BSD-3-Clause license. * Distributed under terms of the BSD-3-Clause license.
*/ */
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state = { const state = {
authStatus: null, authStatus: false,
}; };
const getters = { const getters = {
@ -27,9 +22,9 @@ const mutations = {
}, },
}; };
export default new Vuex.Store({ export default {
state, state,
getters, getters,
mutations, mutations,
}); };

View File

@ -0,0 +1,25 @@
/*
* index.js
* Copyright (C) 2019 pavle <pavle.portic@tilda.center>
*
* Distributed under terms of the BSD-3-Clause license.
*/
import Vue from 'vue';
import Vuex from 'vuex';
import perks from './perks';
import auth from './auth';
Vue.use(Vuex);
const storeData = {
modules: {
perks,
auth,
},
};
export default new Vuex.Store(storeData);

View File

@ -0,0 +1,27 @@
/*
* perks.js
* Copyright (C) 2019 pavle <pavle.portic@tilda.center>
*
* Distributed under terms of the BSD-3-Clause license.
*/
const state = {
perks: [],
};
const getters = {
perks: (state) => state.perks,
};
const mutations = {
setPerks(perks) {
state.perks = perks;
},
};
export default {
state,
getters,
mutations,
};

View File

@ -6,8 +6,8 @@
*/ */
module.exports = { module.exports = {
devServer: { devServer: {
disableHostCheck: true, disableHostCheck: true,
public: 'perktree.localhost', public: 'perktree.localhost',
}, },
}; };