#29 refactor: replace admin code with role-based auth using Pinia

This commit is contained in:
mono
2026-03-14 22:55:24 -05:00
parent 2c9ea4b871
commit 786d0551bb
12 changed files with 105 additions and 129 deletions

View File

@@ -1,51 +0,0 @@
<template>
<v-dialog v-model="dialog" persistent>
<v-card>
<v-card-title>
Ingrese el código
</v-card-title>
<v-card-text>
<v-form id="code-form" @submit.prevent="verifyCode">
<v-text-field v-model="code" label="Código" type="password" autocomplete="off" />
</v-form>
</v-card-text>
<v-card-actions>
<v-btn type="submit" form="code-form" color="green">Aceptar</v-btn>
<v-btn :to="{ path: '/' }" color="red">Cancelar</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import { inject } from 'vue';
export default {
data() {
return {
api: inject('api'),
dialog: true,
code: '',
};
},
methods: {
verifyCode() {
this.api.isValidAdminCode(this.code)
.then(data => {
if (data['validCode']) {
this.$emit('code-verified', true);
this.dialog = false;
} else {
alert('Código incorrecto');
this.$emit('code-verified', false);
}
})
.catch(error => {
alert('Error al validar el código');
this.$emit('code-verified', false);
console.error(error);
});
}
},
}
</script>

View File

@@ -79,9 +79,14 @@
<script> <script>
import trytonIcon from '../assets/icons/tryton-icon.svg'; import trytonIcon from '../assets/icons/tryton-icon.svg';
import AuthService from '@/services/auth'; import AuthService from '@/services/auth';
import { useAuthStore } from '@/stores/auth';
import { inject } from 'vue'; import { inject } from 'vue';
export default { export default {
name: 'NavBar', name: 'NavBar',
setup() {
const authStore = useAuthStore();
return { authStore };
},
data: () => ({ data: () => ({
drawer: false, drawer: false,
group: null, group: null,
@@ -132,6 +137,7 @@
async fetchUser() { async fetchUser() {
try { try {
this.user = await this.api.getCurrentUser(); this.user = await this.api.getCurrentUser();
this.authStore.setUser(this.user);
} catch (error) { } catch (error) {
console.error('Error fetching user:', error); console.error('Error fetching user:', error);
} }
@@ -150,6 +156,7 @@
AuthService.logout(); AuthService.logout();
this.isAuthenticated = false; this.isAuthenticated = false;
this.user = null; this.user = null;
this.authStore.clearUser();
this.$router.push('/'); this.$router.push('/');
}, },
} }

View File

@@ -1,20 +1,19 @@
<template> <template>
<div> <AdminPurchase v-if="authStore.isAdmin"/>
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<AdminPurchase v-if="showComponent"/>
</template> </template>
<script > <script >
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
export default { export default {
data() { setup() {
return { const authStore = useAuthStore();
showComponent: false, return { authStore };
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
components: { CodeDialog },
methods: {},
} }
</script> </script>

View File

@@ -1,20 +1,19 @@
<template> <template>
<div> <ReconciliationJar v-if="authStore.isAdmin" />
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<ReconciliationJar v-if="showComponent" />
</template> </template>
<script > <script >
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
export default { export default {
data() { setup() {
return { const authStore = useAuthStore();
showComponent: false, return { authStore };
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
components: { CodeDialog },
methods: {},
} }
</script> </script>

View File

@@ -1,20 +1,19 @@
<template> <template>
<div> <ReconciliationJarIndex v-if="authStore.isAdmin" />
<CodeDialog @code-verified="(verified) => showComponent = verified" />
</div>
<ReconciliationJarIndex v-if="showComponent" />
</template> </template>
<script> <script>
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
export default { export default {
data() { setup() {
return { const authStore = useAuthStore();
showComponent: false, return { authStore };
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
components: { CodeDialog },
methods: {},
} }
</script> </script>

View File

@@ -1,8 +1,5 @@
<template> <template>
<div> <v-container v-if="authStore.isAdmin" class="fill-height d-flex align-center justify-center">
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<v-container class="fill-height d-flex align-center justify-center">
<v-card class="pa-6" max-width="600" elevation="4"> <v-card class="pa-6" max-width="600" elevation="4">
<v-card-title class="text-h5 font-weight-bold text-center"> <v-card-title class="text-h5 font-weight-bold text-center">
🔄 Sincronización de Clientes 🔄 Sincronización de Clientes
@@ -44,11 +41,15 @@
</template> </template>
<script> <script>
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
import { inject } from 'vue'; import { inject } from 'vue';
export default { export default {
name: 'CustomersFromTryton', name: 'CustomersFromTryton',
setup() {
const authStore = useAuthStore();
return { authStore };
},
data() { data() {
return { return {
api: inject('api'), api: inject('api'),
@@ -59,18 +60,21 @@
updated_customers: [], updated_customers: [],
} }
}, },
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
}
},
methods: { methods: {
startSync() { startSync() {
this.api.getCustomersFromTryton() this.api.getCustomersFromTryton()
.then(response => { .then(response => {
// Manejar la respuesta exitosa
this.checked_tryton_parties = response.checked_tryton_parties.map(id => ({ id })); this.checked_tryton_parties = response.checked_tryton_parties.map(id => ({ id }));
this.created_customers = response.created_customers.map(id => ({ id })); this.created_customers = response.created_customers.map(id => ({ id }));
this.failed_parties = response.failed_parties.map(id => ({ id })); this.failed_parties = response.failed_parties.map(id => ({ id }));
this.untouched_customers = response.untouched_customers.map(id => ({ id })); this.untouched_customers = response.untouched_customers.map(id => ({ id }));
}) })
.catch(error => { .catch(error => {
// Manejar el error
console.error("Error al sincronizar clientes:", error); console.error("Error al sincronizar clientes:", error);
}); });
} }

View File

@@ -1,8 +1,5 @@
<template> <template>
<div> <v-container v-if="authStore.isAdmin" class="fill-height d-flex align-center justify-center">
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<v-container class="fill-height d-flex align-center justify-center">
<v-card class="pa-6" max-width="600" elevation="4"> <v-card class="pa-6" max-width="600" elevation="4">
<v-card-title class="text-h5 font-weight-bold text-center"> <v-card-title class="text-h5 font-weight-bold text-center">
🔄 Sincronización de Productos 🔄 Sincronización de Productos
@@ -39,16 +36,24 @@
</template> </template>
<script> <script>
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
import { inject } from 'vue'; import { inject } from 'vue';
export default { export default {
name: 'ProductsFromTryton', name: 'ProductsFromTryton',
setup() {
const authStore = useAuthStore();
return { authStore };
},
data() { data() {
return { return {
api: inject('api'), api: inject('api'),
productos_tryton: [{}], productos_tryton: [{}],
showComponent: false, }
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
methods: { methods: {

View File

@@ -1,8 +1,5 @@
<template> <template>
<div> <v-container v-if="authStore.isAdmin" class="fill-height d-flex align-center justify-center">
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<v-container class="fill-height d-flex align-center justify-center">
<v-card class="pa-6" max-width="600" elevation="4"> <v-card class="pa-6" max-width="600" elevation="4">
<v-card-title class="text-h5 font-weight-bold text-center"> <v-card-title class="text-h5 font-weight-bold text-center">
🔄 Sincronización de Ventas 🔄 Sincronización de Ventas
@@ -35,16 +32,24 @@
</v-container> </v-container>
</template> </template>
<script> <script>
import CodeDialog from '../components/CodeDialog.vue'; import { useAuthStore } from '@/stores/auth';
import { inject } from 'vue'; import { inject } from 'vue';
export default { export default {
name: 'SalesToTryton', name: 'SalesToTryton',
setup() {
const authStore = useAuthStore();
return { authStore };
},
data() { data() {
return { return {
api: inject('api'), api: inject('api'),
ventas_tryton: [], ventas_tryton: [],
showComponent: false, }
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
methods: { methods: {

View File

@@ -1,19 +1,18 @@
<template> <template>
<div> <ExportPurchasesForTryton v-if="authStore.isAdmin" />
<CodeDialog @code-verified="(verified) => showComponent = verified"/>
</div>
<ExportPurchasesForTryton v-if="showComponent" />
</template> </template>
<script> <script>
import CodeDialog from '../components/CodeDialog.vue' import { useAuthStore } from '@/stores/auth';
export default { export default {
data() { setup() {
return { const authStore = useAuthStore();
showComponent: false, return { authStore };
},
mounted() {
if (!this.authStore.isAdmin) {
this.$router.push('/');
} }
}, },
components: { CodeDialog },
methods: {},
} }
</script> </script>

View File

@@ -31,10 +31,6 @@ class Api {
return this.apiImplementation.getReconciliation(reconciliationId); return this.apiImplementation.getReconciliation(reconciliationId);
} }
isValidAdminCode(code) {
return this.apiImplementation.isValidAdminCode(code);
}
createPurchase(purchase) { createPurchase(purchase) {
return this.apiImplementation.createPurchase(purchase); return this.apiImplementation.createPurchase(purchase);
} }

View File

@@ -49,11 +49,6 @@ class DjangoApi {
return this.getRequest(url); return this.getRequest(url);
} }
isValidAdminCode(code) {
const url = this.base + `/don_confiao/api/admin_code/validate/${code}`
return this.getRequest(url)
}
createPurchase(purchase) { createPurchase(purchase) {
const url = this.base + '/don_confiao/api/sales/'; const url = this.base + '/don_confiao/api/sales/';
return this.postRequest(url, purchase); return this.postRequest(url, purchase);

19
src/stores/auth.js Normal file
View File

@@ -0,0 +1,19 @@
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null
}),
getters: {
isAdmin: (state) => state.user?.role === 'administrator',
isAuthenticated: (state) => !!state.user
},
actions: {
setUser(user) {
this.user = user
},
clearUser() {
this.user = null
}
}
})