diff --git a/api/repositories/user-repository.js b/api/repositories/user-repository.js index 88c7046..bbdeb0f 100644 --- a/api/repositories/user-repository.js +++ b/api/repositories/user-repository.js @@ -31,7 +31,7 @@ class UserRepository { }) .catch(() => { reject({ - "message": "Database error, couldn't get all users.", + "message": "Erreur de base de données, les utilisateurs n'ont pas pu être récupérés.", "code": 500 }) }) @@ -48,7 +48,7 @@ class UserRepository { }) .catch(err => { reject({ - "message": "User with this UUID was not found.", + "message": "L'utilisateur avec cet UUID n'a pas été trouvé.", "code": 404 }) }) @@ -65,7 +65,7 @@ class UserRepository { }) .catch(() => { reject({ - "message": "User with this email was not found.", + "message": "L'utilisateur avec cet email n'a pas été trouvé.", "code": 404 }) }) @@ -77,17 +77,17 @@ class UserRepository { // Checks if body exists and if the model fits, and throws errors if it doesn't if (isEmptyObject(u)) { reject({ - "message": "Request body cannot be empty.", + "message": "Le corps de requête ne peut être vide.", "code": 403 }) } else if (!v.validate(u, UserValidation).valid) { reject({ - "message": "Schema is not valid - " + v.validate(u, UserValidation).errors, + "message": "Structure de la requête invalide - " + v.validate(u, UserValidation).errors, "code": 403 }) } else if (isXSSAttempt(u.name) || isXSSAttempt(u.password) || isXSSAttempt(u.mail)) { reject({ - "message": "Injection attempt detected, aborting the request.", + "message": "Essai d'injection détecté, avortement de la requête.", "code": 403 }) } else { @@ -115,13 +115,14 @@ class UserRepository { }) .then(newUser => { resolve({ - "message": "Account successfully created !", + "message": `Compte utilisateur #${newUser.id} créé avec succès.`, + "code": 201, "user": newUser, }) }) .catch(err => { resolve({ - "message": "An error has occured while creating your account.", + "message": "Une erreur s'est produite en créant votre compte. Veuillez réessayer ultérieurement ou contactez l'administrateur.", "code": 500, }) }) @@ -145,12 +146,14 @@ class UserRepository { if (match) { resolve({ - "message": "User successfully logged in !", + "message": `L'utilisateur #${fetchedUser.id} s'est connecté.`, + "code": 200, "user": fetchedUser, }) } else { reject({ - "message": "Les informations de connexion sont erronées.", + "message": "Les informations de connexions sont erronées.", + "code": 400, }) } }) @@ -163,18 +166,34 @@ class UserRepository { // Check if one user already has that email checkIfEmailAvailable(mail) { return new Promise((resolve, reject) => { + + if (!this.validateEmail(mail)) { + reject({ + "message": "La requête n'est pas un email valide.", + "code": 400, + }) + } + this.getOneByEmail(mail, false) .then(() => { reject({ - "message": "L'email est déjà utilisé par un autre utilisateur.", - "code": 403 + "message": "Cet email est déjà lié à un compte.", + "code": 409 }) }) .catch(() => { - resolve(true) + resolve({ + "message": "Cet email est disponible.", + "code": 200 + }) }) }) } + + validateEmail(email) { + const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(String(email).toLowerCase()); + } } module.exports = UserRepository \ No newline at end of file diff --git a/api/routes/users.js b/api/routes/users.js index 6219953..8e0ac19 100644 --- a/api/routes/users.js +++ b/api/routes/users.js @@ -17,7 +17,6 @@ const Users = new UserRepository(); const getUsers = () => { return Users.getAll() .catch(err => { - console.log(err) throw err }) } @@ -38,11 +37,10 @@ router.get('/', async (req, res) => { }) -// GET ONE FORM UUID ------------------ +// GET ONE FROM UUID ------------------ const getUserByUUID = (uuid) => { return Users.getOneByUUID(uuid) .catch(err => { - console.log(err) throw err }) } @@ -63,11 +61,34 @@ router.get('/:uuid/', async (req, res) => { }) +// CHECK IF MAIL IS AVAILABLE ------------------ +const checkIfEmailAvailable = (mail) => { + return Users.checkIfEmailAvailable(mail) + .catch(err => { + throw err + }) +} +router.get('/available/:mail/', async (req, res) => { + checkIfEmailAvailable(req.params.mail) + .then(v => { + res.setHeader('Content-Type', 'application/json;charset=utf-8') + res.end(JSON.stringify(v)) + }) + .catch(err => { + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + }) +}) + + // LOG A USER ------------------ const logUser = (mail, password) => { return Users.logUser(mail, password) .catch(err => { - console.log(err) throw err }) } diff --git a/client/src/api/usersRepository.js b/client/src/api/usersRepository.js index 2e041a9..a3a9708 100644 --- a/client/src/api/usersRepository.js +++ b/client/src/api/usersRepository.js @@ -3,10 +3,16 @@ import api from './api' const resource = "/users" export default { - login(data) { - return api.post(`${resource}/login`, data) - }, - register(data) { - return api.post(`${resource}`, data) - }, + getOneFromUUID(uuid) { + return api.get(`${resource}/${uuid}`,) + }, + checkEmailAvailable(mail) { + return api.get(`${resource}/available/${mail}`) + }, + login(data) { + return api.post(`${resource}/login`, data) + }, + register(data) { + return api.post(`${resource}`, data) + }, } \ No newline at end of file diff --git a/client/src/components/global/navbar/navbar.vue b/client/src/components/global/navbar/navbar.vue index aac51ae..59a6df3 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -1,60 +1,61 @@ diff --git a/client/src/components/spells/edit-spell-card.vue b/client/src/components/spells/edit-spell-card.vue index 0a3d53d..9806c20 100644 --- a/client/src/components/spells/edit-spell-card.vue +++ b/client/src/components/spells/edit-spell-card.vue @@ -61,6 +61,7 @@ diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index 6af67df..8ddec33 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -76,75 +76,77 @@ import { RepositoryFactory } from "~/api/repositories" const Spells = RepositoryFactory.get('spells') export default { - name: 'spell-card', - props: { - spell: Object, - }, - data() { - return { - main_school: this.spell.schools[0].name, - } - }, - created() { - this.main_school = this.main_school.toLowerCase() - }, - computed: { - user() { - return this.$store.state.user - } - }, - methods: { - editSpell(spell) { - this.$emit('editSpell', spell) - }, - deleteSpell(spell) { - Spells.deleteOne(this.spell.id) - .then(() => { - this.$emit('deleteSpell', spell) - }) - } + name: 'spell-card', + props: { + spell: Object, + }, + data() { + return { + main_school: this.spell.schools[0].name, + } + }, + created() { + this.main_school = this.main_school.toLowerCase() + }, + computed: { + user() { + return this.$store.getters.getUserProfile + } + }, + methods: { + editSpell(spell) { + this.$emit('editSpell', spell) }, + deleteSpell(spell) { + Spells.deleteOne(this.spell.id) + .then(() => { + this.$emit('deleteSpell', spell) + }) + } + }, } \ No newline at end of file diff --git a/client/src/main.js b/client/src/main.js index d92181e..e90e995 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -1,17 +1,18 @@ // Core import Vue from 'vue' -import Vuex from 'vuex' import VueRouter from 'vue-router' import App from './app.vue' +// Environment +require('dotenv').config() + +import store from './store' + import Globals from './global-components.js' Globals.forEach(component => { Vue.component(component.name, component) }); -// Environment -require('dotenv').config() - // Cookies import VueCookies from 'vue-cookies' Vue.use(VueCookies) @@ -55,38 +56,6 @@ Vue.filter('truncate', filter) import router from './routes' Vue.use(VueRouter) -// Store -Vue.use(Vuex) -let user = Vue.$cookies.get('U_') - -const store = new Vuex.Store({ - state: user ? - { status: { loggedIn: true }, user } - : { status: { loggedIn: false }, user: null }, - mutations: { - loginSucceed (state, user) { - state.status.loggedIn = true - state.user = user - }, - loginFail (state) { - state.status.loggedIn = false - state.user = null - }, - logout(state) { - state.status.loggedIn = false; - state.user = null; - }, - registerSucceed (state, user) { - state.status.loggedIn = true - state.user = user - }, - registerFail (state) { - state.status.loggedIn = false - state.user = null - }, - } -}) - // Mount Vue const app = new Vue({ render: h => h(App), diff --git a/client/src/pages/spells/single-spell-page.vue b/client/src/pages/spells/single-spell-page.vue index a6af9a5..dbaf519 100644 --- a/client/src/pages/spells/single-spell-page.vue +++ b/client/src/pages/spells/single-spell-page.vue @@ -1,13 +1,13 @@ \ No newline at end of file diff --git a/client/src/pages/user/profile-page.vue b/client/src/pages/user/profile-page.vue index 61d836c..be7234f 100644 --- a/client/src/pages/user/profile-page.vue +++ b/client/src/pages/user/profile-page.vue @@ -1,24 +1,40 @@ \ No newline at end of file diff --git a/client/src/pages/user/register-page.vue b/client/src/pages/user/register-page.vue index f55518c..e493d30 100644 --- a/client/src/pages/user/register-page.vue +++ b/client/src/pages/user/register-page.vue @@ -1,143 +1,193 @@ diff --git a/client/src/routes.js b/client/src/routes.js index fa1f340..12668aa 100644 --- a/client/src/routes.js +++ b/client/src/routes.js @@ -1,6 +1,7 @@ -import Vue from 'vue' import VueRouter from 'vue-router' +// import store from './store' + // Pages import Index from "~/pages/index-page" @@ -18,80 +19,84 @@ import Profile from "~/pages/user/profile-page" // Routes const routes = [ - { - path: "*", - redirect: "/", - }, - { - path: '/', - component: Index, - }, - { - path: '/connexion', - component: Login, - meta: { - antiAuthGuard: true - } - }, - { - path: '/inscription', - component: Register, - meta: { - antiAuthGuard: true - } - }, - { - path: '/sorts', - component: Spells, - }, - { - path: '/sorts/:id', - component: SpellSingle, - props: true, - }, - { - path: '/ecoles', - component: Schools, - }, - { - path: '/ecoles/:id', - component: SchoolSingle, - props: true, - }, - { - path: '/ages', - component: Timeline, - }, - { - path: '/profil', - component: Profile, - props: true, - meta: { - authGuard: true, - } - }, + { + path: "*", + redirect: "/", + }, + { + path: '/', + component: Index, + }, + { + path: '/connexion', + component: Login, + meta: { + loginFilter: true + } + }, + { + path: '/inscription', + component: Register, + meta: { + loginFilter: true + } + }, + { + path: '/sorts', + component: Spells, + }, + { + path: '/sorts/:id', + component: SpellSingle, + props: true, + }, + { + path: '/ecoles', + component: Schools, + }, + { + path: '/ecoles/:id', + component: SchoolSingle, + props: true, + }, + { + path: '/ages', + component: Timeline, + }, + { + path: '/profil', + component: Profile, + props: true, + meta: { + logoutFilter: true, + } + }, ] const router = new VueRouter({ - mode: 'history', - routes, - linkActiveClass: "", - linkExactActiveClass: "active", + mode: 'history', + routes, + linkActiveClass: "", + linkExactActiveClass: "active", }) -router.beforeEach((to, from, next) => { - if (to.matched.some(record => record.meta.authGuard)) { - if (Vue.$cookies.get('U_') == null) { - next({ - path: '/connexion', - params: { nextUrl: to.fullPath }, - }) - } else { - next() - } - } else { - next() - } -}) +// router.beforeEach((to, from, next) => { +// if (to.matched.some(record => record.meta.loginFilter)) { +// if (store.getters.getUserProfile) { +// next({ +// path: '/', +// }); +// } +// next(); +// } else if (to.matched.some(record => record.meta.logoutFilter)) { +// if (!store.getters.getUserProfile) { +// next({ +// path: '/connexion', +// }); +// } +// next(); +// } +// next(); +// }) export default router; \ No newline at end of file diff --git a/client/src/store/index.js b/client/src/store/index.js new file mode 100644 index 0000000..22d2bb0 --- /dev/null +++ b/client/src/store/index.js @@ -0,0 +1,19 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; + +import VueCookies from 'vue-cookies'; +Vue.use(VueCookies); +Vue.$cookies.config('30d','',''); + +Vue.use(Vuex); + +import user from './modules/user.store'; + +const debug = process.env.NODE_ENV !== 'production'; + +export default new Vuex.Store({ + modules: { + user + }, + strict: debug +}); \ No newline at end of file diff --git a/client/src/store/modules/spell.store.js b/client/src/store/modules/spell.store.js new file mode 100644 index 0000000..0547e28 --- /dev/null +++ b/client/src/store/modules/spell.store.js @@ -0,0 +1,23 @@ +const state = { + +} + +const getters = { + +} + +const actions = { + +} + +const mutations = { + +} + +export default { + namespaced: true, + state, + getters, + actions, + mutations, +} \ No newline at end of file diff --git a/client/src/store/modules/user.store.js b/client/src/store/modules/user.store.js new file mode 100644 index 0000000..33424a9 --- /dev/null +++ b/client/src/store/modules/user.store.js @@ -0,0 +1,88 @@ +// import cookie from 'vue-cookies'; + +// API +import { RepositoryFactory } from "~/api/repositories"; +const Users = RepositoryFactory.get('users'); + +export const namespaced = true; + +const state = { + status: { + logged: false, + profile: null, + } +}; + +const getters = { + + getUserProfile: state => { + if (state.status.logged) { + return state.status.profile + } else { + return false + } + } +}; + +const mutations = { + loginUser(state, user) { + state.status.profile = user; + state.status.logged = true; + }, + + logoutUser(state) { + state.status.profile = null; + state.status.logged = false; + }, + + registerUser() { + + } +}; + +const actions = { + user_login ({ commit }, data) { + return new Promise((resolve, reject) => { + Users.login(data) + .then(v => { + let user = v.data.user; + // cookie.set('user_token', user.uuid); + commit('loginUser', user); + resolve(user); + }) + .catch(err => { + reject(err.response); + }); + }) + }, + + user_logout ({ commit }) { + // cookie.remove('user_token'); + commit('logoutUser'); + }, + + user_register ({ commit }, data) { + return new Promise((resolve, reject) => { + Users.register(data) + .then(() => { + commit('registerUser'); + resolve(); + }) + .catch(err => { + reject(err.response); + }); + }) + } +}; + +// Check if a cookie with user token exists +// if (cookie.get('user_token')) { +// mutations.loginUser(state, cookie.get('user_token')); +// } + +export default { + state, + getters, + actions, + mutations, +}; diff --git a/client/vue.config.js b/client/vue.config.js index e18e3db..9c7389f 100644 --- a/client/vue.config.js +++ b/client/vue.config.js @@ -1,20 +1,20 @@ const path = require('path') module.exports = { - configureWebpack: { - resolve: { - alias: { - "~": path.resolve(__dirname, 'src/') - } - } - }, - css: { - loaderOptions: { - scss: { - prependData: ` - @import "@/assets/scss/_variables.scss"; - ` - } - } + configureWebpack: { + resolve: { + alias: { + "~": path.resolve(__dirname, 'src/') + } } + }, + css: { + loaderOptions: { + scss: { + prependData: ` + @import "@/assets/scss/_variables.scss"; + ` + } + } + } }; \ No newline at end of file