From 0fd933ba99def6b4d15b20d5173733b919c3c7a6 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Wed, 17 Jun 2020 17:52:46 +0200 Subject: [PATCH 01/31] - Made is_ritual visible --- client/src/components/spells/spell-card.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index 5e70f33..c476865 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -23,6 +23,10 @@ Charge {{spell.charge}} tour(s) +
+ Rituel +
+
Nécessite From 86ce421725c02351d142542d79adaf47eef853dd Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Wed, 17 Jun 2020 20:42:27 +0200 Subject: [PATCH 02/31] - commented out things I won't have the time to think about --- client/src/components/spells/add-spell-card.vue | 2 -- client/src/components/spells/edit-spell-card.vue | 7 +++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/components/spells/add-spell-card.vue b/client/src/components/spells/add-spell-card.vue index bc46da1..94141f5 100644 --- a/client/src/components/spells/add-spell-card.vue +++ b/client/src/components/spells/add-spell-card.vue @@ -143,8 +143,6 @@ export default { ingredients: ingredientsData, } - console.log(data) - Spells.addSpell(data) .then(v => { this.$emit('addSpell', v.data) diff --git a/client/src/components/spells/edit-spell-card.vue b/client/src/components/spells/edit-spell-card.vue index 2ad4c2d..fbf451f 100644 --- a/client/src/components/spells/edit-spell-card.vue +++ b/client/src/components/spells/edit-spell-card.vue @@ -13,7 +13,7 @@ @@ -160,6 +161,8 @@ export default { } }, methods: { + cloneSpell() { + }, updateSpell(e) { e.preventDefault() From 49bddf0939b44ab3dab90c5cefdd2f508a6985ce Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Fri, 19 Jun 2020 12:04:01 +0200 Subject: [PATCH 03/31] - Fixed database structure to allow for csv imports --- client/src/components/spells/spell-card.vue | 4 +- database/auracle_db_create.sql | 116 ++++++++-- database/auracle_db_data.sql | 241 -------------------- database/auracle_db_schools.sql | 23 ++ 4 files changed, 126 insertions(+), 258 deletions(-) delete mode 100644 database/auracle_db_data.sql create mode 100644 database/auracle_db_schools.sql diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index c476865..1bef45b 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -41,8 +41,8 @@ v-b-tooltip.click placement="bottom" title="Description copiée !" - class="small text-muted font-italic mt-2"> - {{spell.description}} + class="small text-muted mt-2"> + {{spell.description}}
diff --git a/database/auracle_db_create.sql b/database/auracle_db_create.sql index 9e5d75e..fdbdb4b 100644 --- a/database/auracle_db_create.sql +++ b/database/auracle_db_create.sql @@ -2,18 +2,43 @@ DROP DATABASE IF EXISTS auracle; CREATE DATABASE auracle CHARACTER SET utf8 COLLATE utf8_bin; USE auracle; -/* ==== PRIMARY TABLES ==== */ +/* =========== PRIMARY TABLES =========== */ + +/* PERMISSIONS */ +CREATE TABLE IF NOT EXISTS `role` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `description` VARCHAR(255) NOT NULL, + PRIMARY KEY(`id`) +); + +/* USERS */ +CREATE TABLE IF NOT EXISTS `user` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL DEFAULT "Disciple", + `mail` VARCHAR(255) NOT NULL, + `password` VARCHAR(255) NOT NULL, + `role_id` INT UNSIGNED NOT NULL DEFAULT 1, + `verified` BOOLEAN DEFAULT false, + `banned` BOOLEAN DEFAULT false, + PRIMARY KEY(`id`), + FOREIGN KEY(`role_id`) REFERENCES role(`id`) +); /* SPELLS */ CREATE TABLE IF NOT EXISTS `spell` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL DEFAULT 'Nom du sort', + `name` VARCHAR(255) NOT NULL DEFAULT "Nom du sort", `description` VARCHAR(1000) NOT NULL DEFAULT "Description du sort", `level` INT UNSIGNED DEFAULT 0, `charge` INT UNSIGNED DEFAULT 0, `cost` VARCHAR(255) DEFAULT "0", `is_ritual` BOOLEAN DEFAULT false, - PRIMARY KEY (`id`) + `published` BOOLEAN DEFAULT true, + `public` BOOLEAN DEFAULT true, + `author_id` INT UNSIGNED NOT NULL DEFAULT 1, + PRIMARY KEY (`id`), + FOREIGN KEY(`author_id`) REFERENCES user(`id`) ); /* META SCHOOLS */ @@ -38,7 +63,7 @@ CREATE TABLE IF NOT EXISTS `school` ( CREATE TABLE IF NOT EXISTS `ingredient` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL DEFAULT "Langue de salamandre", - `description` VARCHAR(255) NOT NULL DEFAULT "Une langue de salamandre de feu qui bouge encore un peu.", + `description` VARCHAR(255) NOT NULL DEFAULT "Une langue de salamandre de feu encore chaude.", PRIMARY KEY (`id`) ); @@ -49,17 +74,6 @@ CREATE TABLE IF NOT EXISTS `variable` ( PRIMARY KEY (`id`) ); -/* ==== USER TABLES ==== */ - -CREATE TABLE IF NOT EXISTS `user` ( - `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL DEFAULT "Disciple", - `mail` VARCHAR(255) NOT NULL, - `password` VARCHAR(255) NOT NULL, - `banned` BOOLEAN DEFAULT false, - PRIMARY KEY(`id`) -); - /* ==== ASSOCIATION TABLES ==== */ /* SPELLS' SCHOOLS */ @@ -91,3 +105,75 @@ CREATE TABLE IF NOT EXISTS `spell_ingredient` ( FOREIGN KEY(`spell_id`) REFERENCES spell(`id`), FOREIGN KEY(`ingredient_id`) REFERENCES ingredient(`id`) ); + +/* Ajout d'une nouvelle ligne avant l'insert de description */ +DELIMITER $$ +CREATE TRIGGER `multiLine` BEFORE INSERT ON `spell` FOR EACH ROW +BEGIN + SET NEW.description = replace(NEW.description, '', '\n'); +END$$ +DELIMITER ; + + + +/* =========== PRIMARY INSERTS =========== */ +SET NAMES utf8; +USE auracle; + +-- PERMISSIONS +INSERT INTO `role` (name, description) VALUES +('Visiteur', "Utilisateur normal, peut consulter les sorts."), +('Scribe', "Gardiens des écrits, est capable de modifier et d'ajouter des sorts."), +('Arcanologue', "Maîtres de l'arcane, ils ont le pouvoir et la responsabilité de juger les sortilèges récents et de les supprimer, ou valider."), +('Augure', "Régents des grimoires, ils ont droit d'accès à l'intégralité des informations connues, et pouvoir absolu sur le savoir arcanique."); + +-- USERS +INSERT INTO `user` (name, mail, password, role_id) VALUES +('Izàc Tymos', 'tymos@ambrose.edu', 'root', 4); + +-- META SCHOOLS +INSERT INTO `meta_school` (name, description) VALUES +('Magies blanches', 'Magies disciplinant les arts de soins et de lumières.'), +('Magies noires', 'Magies disciplinant l\'art de la mort et des secrets.'), +('Magies élémentaires', 'Magies disciplinant les éléments basiques tels que l\'eau, la foudre et le feu, pour n\'en citer que les plus populaires.'), +('Magies spirituelles', 'Magies disciplinant l\'esprit, tant pour le défendre que l\'attaquer.'), +('Magies spatio-temporelles', 'Magies régissant le temps et l\'espace.'), +('Magies affiliées', 'Magies rattachées à une forme d\'énergie magique particulière.'), +('Magies autres', 'Magies trop spécifiques et ne rentrant dans aucune autre grande école.'); + +-- SCHOOLS +INSERT INTO `school` (name, description, meta_school_id) VALUES +('Lumomancie', 'Discipline arcanique de la lumière.', 1), +('Vitamancie', 'Discipline arcanique de la guérison et de l\'énergie vitale.', 1), +('Obstrumancie', 'Discipline arcanique de la protection et des sceaux.', 1), +('Tenebromancie', 'Discipline arcanique de la lumière.', 2), +('Necromancie', 'Discipline arcanique de la mort.', 2), +('Morbomancie', 'Discipline arcanique des maladies et malédictions.', 2), +('Pyromancie', 'Discipline arcanique du feu.', 3), +('Hydromancie', 'Discipline arcanique de l\'eau.', 3), +('Electromancie', 'Discipline arcanique de la foudre.', 3), +('Terramancie', 'Discipline arcanique de la terre.', 3), +('Sidéromancie', 'Discipline arcanique des métaux rares et précieux.', 3), +('Caelomancie', 'Discipline arcanique de l\'air.', 3), +('Légimancie', 'Discipline arcanique de la lecture et du contrôle spirituel.', 4), +('Illusiomancie', 'Discipline arcanique des illusions.', 4), +('Cruciomancie', 'Discipline arcanique de la destruction spirituelle.', 4), +('Chronomancie', 'Discipline arcanique du temps.', 5), +('Spatiomancie', 'Discipline arcanique de l\'espace.', 5), +('Kénomancie', 'Discipline arcanique du néant.', 6), +('Lutomancie', 'Discipline arcanique des abysses.', 6), +('Échomancie', 'Discipline arcanique de la résolution animique.', 6), +('Protomancie', 'Discipline arcanique de la magie pure.', 7), +('Rebumancie', 'Discipline arcanique de la lumière.', 7), +('Vocamancie', 'Discipline arcanique de la lumière.', 7), +('Somamancie', 'Discipline arcanique de la maîtrise corporelle.', 7), +('Antimancie', 'Discipline arcanique de l\'annulation arcanique.', 7); + +-- INGREDIENTS +INSERT INTO `ingredient` (name, description) VALUES +('Volonté', 'La force de volonté du lanceur, concentrée sur un objectif'), +('Geste', 'Un geste précis facilitant la canalisation magique'); + +-- VARIABLES +INSERT INTO `variable` (description) VALUES +('Nombre de personnes soignées'); \ No newline at end of file diff --git a/database/auracle_db_data.sql b/database/auracle_db_data.sql deleted file mode 100644 index b58cb4d..0000000 --- a/database/auracle_db_data.sql +++ /dev/null @@ -1,241 +0,0 @@ -SET NAMES utf8; -USE auracle; - --- META SCHOOLS -INSERT INTO `meta_school` (name, description) VALUES -('Magies blanches', 'Magies disciplinant les arts de soins et de lumières.'), -('Magies noires', 'Magies disciplinant l\'art de la mort et des secrets.'), -('Magies élémentaires', 'Magies disciplinant les éléments basiques tels que l\'eau, la foudre et le feu, pour n\'en citer que les plus populaires.'), -('Magies spirituelles', 'Magies disciplinant l\'esprit, tant pour le défendre que l\'attaquer.'), -('Magies spatio-temporelles', 'Magies régissant le temps et l\'espace.'), -('Magies affiliées', 'Magies rattachées à une forme d\'énergie magique particulière.'), -('Magies autres', 'Magies trop spécifiques et ne rentrant dans aucune autre grande école.'); - --- SCHOOLS -INSERT INTO `school` (name, description, meta_school_id) VALUES -('Lumomancie', 'Discipline arcanique de la lumière.', 1), -('Vitamancie', 'Discipline arcanique de la guérison et de l\'énergie vitale.', 1), -('Obstrumancie', 'Discipline arcanique de la protection et des sceaux.', 1), -('Tenebromancie', 'Discipline arcanique de la lumière.', 2), -('Necromancie', 'Discipline arcanique de la mort.', 2), -('Morbomancie', 'Discipline arcanique des maladies et malédictions.', 2), -('Pyromancie', 'Discipline arcanique du feu.', 3), -('Hydromancie', 'Discipline arcanique de l\'eau.', 3), -('Electromancie', 'Discipline arcanique de la foudre.', 3), -('Terramancie', 'Discipline arcanique de la terre.', 3), -('Caelomancie', 'Discipline arcanique de l\'air.', 3), -('Légimancie', 'Discipline arcanique de la lecture et du contrôle spirituel.', 4), -('Illusiomancie', 'Discipline arcanique des illusions.', 4), -('Cruciomancie', 'Discipline arcanique de la destruction spirituelle.', 4), -('Chronomancie', 'Discipline arcanique du temps.', 5), -('Spatiomancie', 'Discipline arcanique de l\'espace.', 5), -('Kénomancie', 'Discipline arcanique du néant.', 6), -('Lutomancie', 'Discipline arcanique des abysses.', 6), -('Échomancie', 'Discipline arcanique de la résolution animique.', 6), -('Protomancie', 'Discipline arcanique de la magie pure.', 7), -('Rebumancie', 'Discipline arcanique de la lumière.', 7), -('Vocamancie', 'Discipline arcanique de la lumière.', 7), -('Somamancie', 'Discipline arcanique de la maîtrise corporelle.', 7), -('Antimancie', 'Discipline arcanique de l\'annulation arcanique.', 7); - --- SPELLS -/* -SCHEMA -(name, description, level, charge, cost, is_ritual), -*/ - --- LIGHT SPELLS -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Rayon prismatique I', 'Un petit rayon étincelant est émis de la paume du lanceur. Ce dernier peut rebondir sur les surfaces réfléchissantes. S’il percute une cture, elle subit 6+2D6 dégâts radiants.', 0, 0, '0', false), -('Rayon prismatique II', 'Un rayon étincelant est émis de la paume du lanceur. Ce dernier peut rebondir sur les surfaces réfléchissantes. S’il percute une créature, e subit 15+2D6 dégâts radiants.', 0, 0, '-20', false), -('Rayon prismatique III', 'Un grand rayon étincelant est émis de la paume du lanceur. Ce dernier peut rebondir sur les surfaces réfléchissantes. S’il percute une cture, elle subit 25+2D6 dégâts radiants.', 0, 0, '-40', false), -('Laser prismatique', 'Les mains du lanceur s’illuminent d’une intense aura blanche. Après un tour de canalisation, il projette un énorme laser blanc de sa paume dans une direction unique, infligeant 30+1D20+2D6 dégâts radiants aux créatures sur sa trajectoire. Le laser peut rebondir sur les surfaces réfléchissantes.', 20, 1, '-60', false), - -('Globe lumineux', 'Le lanceur manifeste un petit globe de lumière autour de lui. La lumière dégagée par ce globe éclaire sur une portée initiale de 5m, mais peut être augmentée suivant la puissance du sort. Le lanceur garde un contrôle sur cette sphère, qu’il peut déplacer en conséquence.', 0, 0, '-10x', false), -('Globule de vérité', 'Le lanceur concentre son arcane en un globule de lumière bleue qui flottille autour de lui. Ce dernier, en plus d’être une source de lumière considérable, permet de disperser la magie d’illusion. Le lanceur manifeste un globe de lumière magique éclairant sur 5m autour de lui. Permet de voir les objets et créatures cachés par magie et de percer les illusions.', 10, 0, '-25x', false), - -('Vision nocturne', 'Le lanceur octroie à lui-même ou bien à une créature qu’il touche une vision nettement améliorée dans l’obscurité pendant 1D3 tours.', 0, 0, '-20', false), -('Œil de Lystos', 'Le lanceur octroie à lui-même ou bien à une créature qu’il touche le statut «Clairvoyant» pendant 1D3 tours. Elle gagne une vision nettement améliorée dans l’obscurité ainsi qu’un avantage pour percevoir à travers la pénombre magique et les illusions.', 10, 0, '-40', false), -('Illumination', 'Par le toucher, le lanceur octroie à un petit objet une luminosité de faible intensité, semblable à la lumière vacillante d’une bougie.', 0, 0, '+20', false), - -('Lumière aveuglante', 'Le lanceur, en claquant des doigts, produit un bref flash de lumière devant une cible, l’aveuglant pendant 1D2 tours.', 0, 0, '0', false), -('Irradiation', 'Le lanceur s’illumine instantanément pendant une fraction de seconde, aveuglant toutes les créatures le regardant dans un rayon de 10m pendant 1D2 tours.', 10, 0, '-25', false), - -('Lystos I', 'Le lanceur, en se concentrant sur l’image de Lystos dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D5+5 dégâts radiants ignorant l\'armure en dégageant une aura brûlante. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -15.', 0, 0, '0', false), -('Lystos II', 'Le lanceur, en se concentrant sur l’image de Lystos dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D8+8 dégâts radiants ignorant l\'armure en dégageant une aura brûlante. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -30.', 0, 0, '-20', false), -('Lystos III', 'Le lanceur, en se concentrant sur l’image de Lystos dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D10+10 dégâts radiants ignorant l\'armure en dégageant une aura brûlante. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -45.', 0, 0, '-40', false), -('Paradigme Lystonien', 'Le lanceur s’imprègne de l’image de Lystos, et la concentre dans son esprit. Son sceau, entouré de plusieurs petits sceaux, se manifestent sous un petit groupe de cibles. Ces dernières sont brûlées par la lumière se dégageant des emblèmes, et subissent 2D20+20 dégâts radiants ignorant l\'armure. Une énergie divine mystérieuse pénètre l’esprit des cibles, ralentissant leurs mouvements et drainant leur volonté. Toute tentative d’esquive subit un malus de -60.', 15, 1, '-60', false), - -('Corps luminescent', 'Le lanceur transmute une partie plus ou moins grande de son corps en énergie luminescente, lui permettant de s’en servir comme extension ou comme arme. La partie transmutée permet de passer à travers les objets et surfaces peu épaisses.', 0, 0, '?', false), - -('Jugement lumineux', 'Le corps du lanceur brille d’une aura blanche tandis qu’il manifeste une guillotine de lumière au niveau du cou d’une cible unique. La lame de lumière passe au travers de sa gorge et lui réduit ses PV de moitié.', 20, 0, '-80', false), - -('Étoile de l\'aube', 'Une sphère de lumière initialement pâle, puis très lumineuse, se manifeste à 20m du sol et du lanceur. Au deuxième tour de canalisation, elle s’abat au sol dans une explosion iridescente, soufflant toutes les créatures dans un rayon de 20m, leur infligeant 60+3D12+3D6 dégâts radiants.', 25, 2, '-120', false), - -('Lumière pourrie I', 'Le lanceur conjure une orbe lumineuse verdâtre jusqu’à 5m autour de lui. Cette dernière, au rythme de ses palpitations, projette des rayons brûlants dans toutes les directions autour d’elle dans un rayon de 20m. Toutes les créatures à découvert dans un rayon de 20m de la sphère (sauf le lanceur) doivent réussir un jet de DEX. Si elles échouent, elles subissent 2D10 dégâts radiants et 1D10 dégâts nécrotiques. Elles perdent également 1D6 PV max.', 20, 0, '-30', false), -('Lumière pourrie II', 'Le lanceur conjure une orbe lumineuse verdâtre jusqu’à 5m autour de lui. Cette dernière, au rythme de ses palpitations, projette des rayons brûlants dans toutes les directions autour d’elle dans un rayon de 20m. Toutes les créatures à découvert dans un rayon de 30m de la sphère (sauf le lanceur) doivent réussir un jet de DEX. Si elles échouent, elles subissent 2D20 dégâts radiants et 1D20 dégâts nécrotiques. Elles perdent également 1D8 PV max.', 20, 0, '-50', false), -('Lumière pourrie III', 'Le lanceur conjure une orbe lumineuse verdâtre jusqu’à 5m autour de lui. Cette dernière, au rythme de ses palpitations, projette des rayons brûlants dans toutes les directions autour d’elle dans un rayon de 20m. Toutes les créatures à découvert dans un rayon de 50m de la sphère (sauf le lanceur) doivent réussir un jet de DEX. Si elles échouent, elles subissent 2D20 dégâts radiants et 2D20 dégâts nécrotiques. Elles perdent également 1D10 PV max.', 25, 0, '-70', false), -('Soleil pourri', 'Le lanceur projette un petit astre vert jusqu’à 20m autour de lui. L’astre brûle l’air environnant, nécrosant rapidement les formes de vies dans un rayon de 100m. Toutes les créatures dans la portée de l’astre (sauf le lanceur) doivent réussir un jet de CON avec un malus de -30. Si elles échouent, elles subissent 3D20 dégâts radiants et 2D20 dégâts nécrotiques. Elles perdent également 1D10 PV max.', 30, 2, '-90', false), - -('Brisaube', 'Le lanceur insufle une arme qu\'il touche d\'une quantité phénoménale de magie lumineuse, de telle sorte à ce qu\'elle brille de milles feux. L\'arme inflige 2D20+1D12 dégâts radiants supplémentaires pendant 3 tours et inflige le statut "Brûlures solaires" pendant 1D4 tours si elle touche une créature.', 50, 0 , '-80', false), - -('Consécration', 'Le lanceur conjure X sphères runiques dans un rayon de 40m autour de lui. Après un court instant, ces dernières explosent d\'une vive lumière blanche, infligeant 2D8+2D6 dégâts radiants aux créatures se trouvant à au moins 2m autour d\'elles.', 80, 0, '-15x', false), -('Apothéose', 'Un cercle runique apparait derrière le lanceur. Ce dernier manifeste des centaines de petits cristaux de lumière en son bord qui fondent sur les cibles dans le champ de vision du lanceur, infligeant 4D2*4D2 dégâts à chacune d\'entre elles.', 80, 1, '-100', false); - -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Guérison I', 'Rend 2D4+4 PV, soigne les contusions légères et blessures superficielles.', 0, 0, '0', false), -('Guérison II', 'Rend 2D6+6 PV, soigne les blessures mineures.', 0, 0, '-10', false), -('Guérison III', 'Rend 2D10+10 PV, soigne les blessures profondes.', 0, 0, '-20', false), -('Guérison IV', 'Rend 2D20+20 PV, soigne les blessures graves et stoppe les hémorragies.', 0, 0, '-40', false), -('Thaumaturgie', 'Débordant d’altruisme, le lanceur canalise l’arcane autour de lui afin de panser les blessures d’une créature. La créature ciblée regagne 3D20+30 PV. Ses blessures graves se guérissent instantannément et toute hémorragie cesse. Si la cible se trouvait dans un état de mort imminente, elle est considérée comme stabilisée.', 20, 1, '-60', false), - -('Régénération I', 'Rend 1D4+2 PV pendant 3 tours à une créature, soigne les contusions légères et blessures superficielles.', 0, 0, '0', false), -('Régénération II', 'Rend 1D6+3 PV pendant 3 tours à une créatures, soigne les blessures mineures.', 0, 0, '-5', false), -('Régénération III', 'Rend 1D10+5 PV pendant 3 tours à une créature, soigne les blessures profondes.', 0, 0, '-15', false), -('Régénération IV', 'Rend 1D20+10 PV pendant 3 tours à une créature, soigne les blessures graves et stoppe les hémorragies.', 0, 0, '-30', false), -('Argaturgie', 'Le lanceur duplique sa force vitale afin de soigner sur la durée les blessures d\'une créature unique. Elle regagne 3D10+15 PV pendant 3 tours et soigne les blessures et ses hémorragies importantes.', 20, 1, '-50', false), - -('Guérison collective I', 'Rend 1D4+4 PV à plusieurs créatures, soigne les contusions légères et blessures superficielles.', 0, 0, '-2x', false), -('Guérison collective II', 'Rend 1D6+6 PV à plusieurs créatures, soigne les blessures mineures.', 0, 0, '-5x', false), -('Guérison collective III', 'Rend 1D10+10 PV à plusieurs créatures, soigne les blessures profondes.', 0, 0, '-10x', false), -('Guérison collective IV', 'Rend 1D20+20 PV à plusieurs créatures, soigne les blessures graves et stoppe les hémorragies.', 0, 0, '-15x', false), -('Polythurgie', 'Le lanceur transmet de l\'énergie vitale pure à plusieurs créatures. Elles regagnent 3D10+30 PV et leurs hémorragies graves s\'estompent. Si les cibles se trouvaient dans un état de mort imminente, elles sont considérées comme stabilisées.', 20, 1, '-20x', false), - -('Détoxication I', 'Renforce les défenses immunitaires d\'une créature et permet à son corps de se défendre contre un faible poison. Donne +10 CON au prochain jet contre ce dernier.', 0, 0, '0', false), -('Détoxication II', 'Renforce les défenses immunitaires d\'une créature et permet à son corps de se défendre contre un poison. Donne +20 CON aux 2 prochains jets contre ce dernier.', 0, 0, '-10', false), -('Détoxication III', 'Renforce grandement les défenses immunitaires d\'une créature et permet à son corps de se défendre contre un poison sévère. Donne +30 CON aux 2 prochains jets contre ce dernier.', 0, 0, '-30', false), -('Thératurgie', 'Renforce énormément les défenses immunitaires d\'une créature et permet au corps d\'expulser un poison mortel et puissant.', 20, 1, '-50', false), - -('Détection de vie', 'Le lanceur peut déterminer la force vitale restante d\'une créature dans son champ de vision jusqu\'à 15m de distance.', 0, 0, '0', false), -('Œil de Sotana', 'Octroie au lanceur une vision thermique des 5 mètres alentours permettant de voir la force vitale des créatures conscientes environnantes. Plus une forme apparait clairement au lanceur, plus elle est en bonne santé.', 10, 0, '-15x', false), - -('Filin de survie', 'Relie le corps du lanceur à celui d\'une autre créature par un filin de lumière blanche intangible. Les dégâts subis par les deux sont divisés et répartis équitablement pendant 3 tours.', 15, 0, '-30', false), - -('Contre-mort', 'Le lanceur infuse une force vitale conséquente à une cible. Si elle reçoit une attaque fatale, elle conserve un unique point de vie à la place. L\'effet du sort dure une heure.', 15, 0, '-50', false), - -('Sotana', 'En brûlant la moitié de ses PV max, le lanceur concentre sa volonté et son énergie vitale de manière à ramener à 1 PV une créature décédée depuis 2h maximum. Pour que ce sort se conclue, il faut impérativement que l\'âme de la créature ne soit ni détruite ni scellée, et que le lanceur soit en contact avec une partie du corps de la cible, ou une de ses possessions (qui sera consommée par le sort dans les deux cas)', 25, 0, '-80', false), -('Masotana', 'Le lanceur manifeste une zone d\'énergie vitale pure autour de lui sur environ 10m, empêchant à toutes les créatures dans cette zone de mourir pendant 5 tours. Les créatures peuvent toujours être incapacitées et ressentent la douleur, mais ne peuvent pas descendre en dessous de 1 PV.', 30, 1, '-100', false); - -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Bouclier arcanique I', 'Dresse une épaisse barrière d\'énergie magique autour d\'une ou plusieurs personnes, bloquant 15 points de dégâts.', 0, 0, '-10x', false), -('Bouclier arcanique II', 'Dresse une épaisse barrière d\'énergie magique autour d\'une ou plusieurs personnes, bloquant 30 points de dégâts.', 0, 0, '-20x', false), -('Bouclier arcanique III', 'Dresse une épaisse barrière d\'énergie magique autour d\'une ou plusieurs personnes, bloquant 60 points de dégâts.', 0, 0, '-40x', false), -('Isolation arcanique', 'Dresse une épaisse barrière d\'énergie magique pure autour d\'une ou plusieurs personnes, bloquant 100 points de dégâts.', 20, 0, '-60x', false), - -('Bouclier étendu I', 'Conjure une unique barrière magique autour de plusieurs personnes, bloquant 50 points de dégâts avant de se briser.', 10, 0, '-30-10x', false), -('Bouclier étendu II', 'Conjure une unique barrière autour magique de plusieurs personnes, bloquant 90 points de dégâts avant de se briser.', 10, 0, '-50-10x', false), -('Barricades arcaniques', 'Conjure une unique épaisse barrière magique autour de plusieurs personnes, bloquant 120 points de dégâts avant de se briser.', 20, 0, '-70-10x', false), - -('Barrière régénératrice I', 'Le lanceur dresse une barrière protectrice autour d\'une ou plusieurs créature(s), les protégeant de 20 points de dégâts. Les créatures affectées par ce sort regagnent 1D6 PV par tour tant que la barrière persiste.', 15, 0, '-20x', false), -('Barrière régénératrice II', 'Le lanceur dresse une barrière protectrice autour d\'une ou plusieurs créature(s), les protégeant de 40 points de dégâts. Les créatures affectées par ce sort regagnent 2D6 PV par tour tant que la barrière persiste.', 15, 0, '-40x', false), -('Cocon guérisseur', 'Le lanceur dresse une épaisse barrière protectrice brilliante autour d\'une ou plusieurs créature(s), les protégeant de 60 points de dégâts. Les créatures affectées par ce sort regagnent 3D8 PV par tour tant que la barrière persiste.', 20, 0, '-60x', false), - -('Verrou arcanique I', 'Protège de manière magique un objet ouvrable (coffre, livre, etc...). L\'objet est scellé et ne peut plus s\'ouvrir, sauf sur volonté du lanceur. Résiste à 15 points de dégâts magiques. Une personne peut l\'ouvrir si elle inflige assez de dégâts au verrou, ou si elle réussi un jet d\'arcane avec un malus de 20.', 5, 0, '-15', false), -('Verrou arcanique II', 'Protège de manière magique un objet ouvrable (coffre, livre, etc...). L\'objet est scellé et ne peut plus s\'ouvrir, sauf sur volonté du lanceur. Résiste à 30 points de dégâts magiques. Une personne peut l\'ouvrir si elle inflige assez de dégâts au verrou, ou si elle réussi un jet d\'arcane avec un malus de 40.', 10, 0, '-30', false), -('Verrou arcanique III', 'Protège de manière magique un objet ouvrable (coffre, livre, etc...). L\'objet est scellé et ne peut plus s\'ouvrir, sauf sur volonté du lanceur. Résiste à 50 points de dégâts magiques. Une personne peut l\'ouvrir si elle inflige assez de dégâts au verrou, ou si elle réussi un jet d\'arcane avec un malus de 60.', 15, 0, '-50', false), -('Chaînes du souverain', 'Manifeste des chaînes blanches sur un objet (coffre, livre, etc...). L\'objet est scellé et ne peut plus s\'ouvrir, sauf sur volonté du lanceur. Les chaînes se dissipent et ne réapparaissent qu\'avec une tentative d\'effraction. Résiste à 75 points de dégâts magiques. Une personne peut l\'ouvrir si elle inflige assez de dégâts au verrou, ou si elle réussi un jet d\'arcane avec un malus de 90.', 20, 1, '-75', false), - -('Sceau des grands anciens', 'Au court d\'un rituel de canalisation intense et épuisant, le lanceur utilise toute l\'énergie magique de son corps et une partie de sa force vitale afin d\'isoler complètement une chose quelconque de l\'existence, la plaçant effectivement entre les dimensions et du temps. La force et la durabilité du sceau dépend de la force magique du lanceur. Pour un Dieu par exemple, le sceau dure environ 5000 ans. Le sceau n\'est pas indestructible, et est susceptible à l\'usure du temps, des attaques répétées, etc...', 99, 99, '?', true), -('Ascension', 'Réveille la partie de l\'âme scellée d\'une créature, l\'unifiant dans un seul corps, et lui permettant de maitriser l\'échomancie.', 99, 5, '?', false); - --- DARKNESS SPELLS -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Onde noire I', 'Projette une petite onde d\'énergie noire sur 5m autour du lanceur, infligeant 6+2D6 points de dégâts obscurs.', 0, 0, '0', false), -('Onde noire II', 'Projette une onde d\'énergie noire sur 10m autour du lanceur, infligeant 15+2D6 points de dégâts obscurs.', 0, 0, '-20', false), -('Onde noire III', 'Projette une vaste onde d\'énergie noire sur 20m autour du lanceur, infligeant 25+2D6 points de dégâts obscurs.', 0, 0, '-40', false), -('Vibrobscur', 'Projette une vague d\'énergie ténébreuse sur 40m autour du lanceur, infligeant 30+1D20+2D6 points de dégâts obscurs.', 20, 1, '-60', false), - -('Ményl I', 'Le lanceur, en se concentrant sur la forme de Ményl dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D5+5 dégâts obscurs ignorant l\'armure en dégageant une aura glaciale. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -15.', 0, 0, '0', false), -('Ményl II', 'Le lanceur, en se concentrant sur la forme de Ményl dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D8+8 dégâts obscurs ignorant l\'armure en dégageant une aura glaciale. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -30.', 0, 0, '-20', false), -('Ményl III', 'Le lanceur, en se concentrant sur la forme de Ményl dans son esprit, manifeste son sceau sous une cible unique, qui lui inflige 2D10+10 dégâts obscurs ignorant l\'armure en dégageant une aura glaciale. Des énergies divines mystérieuses facilitent la canalisation du sort et sa rapidité. Si la cible tente d’esquiver, son action subit un malus de -45.', 0, 0, '-40', false), -('Vision Ménélienne', 'Le lanceur s’imprègne de l\'énergie de Ményl, et la concentre dans son esprit. Son sceau, entouré de plusieurs petits sceaux, se manifestent sous un petit groupe de cibles. Ces dernières sont brûlées de froid par les ténèbres se dégageant des emblèmes, et subissent 2D20+20 dégâts obscurs ignorant l\'armure. Une énergie divine mystérieuse pénètre l’esprit des cibles, ralentissant leurs mouvements et drainant leur volonté. Toute tentative d’esquive subit un malus de -60.', 15, 1, '-60', false), - -('Corps sombre', 'Le lanceur transmute une partie plus ou moins grande de son corps en énergie ténébreuse, lui permettant de s’en servir comme extension ou comme arme. La partie transmutée permet de passer à travers les objets et surfaces peu épaisses.', 0, 0, '?', false), - -('Sangsue I', 'Une dizaine de petites sphères violacées fusent vers la cible, infligeant 2D8 dégats obscurs. Le lanceur récupère les dégâts subis.', 5, 0, '-10', false), -('Sangsue II', 'Une dizaine de sphères violacées fusent vers la cible, infligeant 4D8 dégats perçants. Le lanceur récupère les dégâts subis.', 5, 0, '-25', false), -('Sangsue III', 'Une dizaine de grandes sphères violacées fusent vers la cible, infligeant 6D8 dégats obscurs. Le lanceur récupère les dégâts subis.', 5, 0, '-50', false), -('Exsangue', 'Une vingtaine de sphères et d\'éclairs noirs frappent la cible, infligeant 8D8 dégâts obscurs. Le lanceur récupère les dégâts subis. La cible doit également faire un jet de CON. En cas d\'échec, elle subit le statut "Fatigue II".', 20, 1, '-75', false), - -('Zona I', 'Le lanceur projette une ombre circulaire au sol qui s\'étend sur 2m de diamètre. Des tentacules noirs se manifestent à sa surface et infligent (1D4)D3 aux entités à maximum 2m de l\'ombre chaque tour. L\'ombre persiste pendant 1D3 tours.', 5, 0, '-20', false), -('Zona II', 'Le lanceur projette une large ombre circulaire au sol qui s\'étend sur 2m de diamètre. Des tentacules noirs se manifestent à sa surface et infligent (1D6)D3 aux entités à maximum 2m de l\'ombre chaque tour. L\'ombre persiste pendant 1D3 tours.', 5, 0, '-40', false), -('Zoness', 'Le lanceur projette un duo d\'ombres circulaires au sol qui s\'étendent sur 4m de diamètre. Des tentacules noirs se manifestent à sa surface et infligent (1D10)D3 aux entités à maximum 3m de l\'ombre chaque tour. L\'ombre persiste pendant 1D4 tours.', 15, 0, '-60', false), - -('Pénombres I', 'Englobe une zone de 5m autour du lanceur dans les ténèbres, diminuant la visibilité.', 0, 0, '-10-20x', false), -('Pénombres II', 'Englobe une zone de 5m autour du lanceur dans les ténèbres, diminuant grandement la visibilité.', 0, 0, '-20-20x', false), -('Pénombres III', 'Englobe une zone de 7m autour du lanceur dans les ténèbres, diminuant énormément la visibilité.', 0, 0, '-30-20x', false), -('Enclave abyssale', 'Englobe une zone de 7m autour du lanceur dans les ténèbres, rendant la visibilité quasi-nulle. Des tentacules d\'énergie noire transpercent les ennemis présents dans la zone, infligeant 2D8 dégâts obscurs par tour.', 15, 0, '-40-20x', false), - -('Aiguillons de l\'ombre', 'Le lanceur manifeste X flèchettes noires qu\'il projette sur une cible, infligeant 1DX+X de dégâts obscurs ignorant l\'armure. La cible doit effectuer un jet de CON avec un malus de X. Si elle échoue, elle gagne le statut "Brisé" pendant 2 tours.', 0, 0, '-2x', false), -('Morsures de la nuit', 'Le lanceur façonne l\'obscurité autour d\'une cible en forme de machoîres noires, qui se referment brutalement sur cette dernière, lui infligeant 2D12+2D8 dégâts obscurs ignorant l\'armure.', 0, 0, '-15', false), -('Un avec les ombres', 'Le lanceur, tapi dans une ombre distincte, se fond en elle. Il surgit ensuite d\'une ombre adjacente de cette dernière dans une portée de 5m. Le lanceur est invulnérable pendant qu\'il se téléporte d\'une ombre à une autre.', 10, 0, '-20', false), - -('Décret de l\'ombre', 'Le corps du lanceur brille d\'une aura sombre et froide tandis qu\'il manifeste une faux noire derrière une cible unique. La lame le fauche et lui réduit ses PV de moitié.', 20, 0, '-80', false), -('Étoile du crépuscule', 'Une sphère noire d\'encre se manifeste dans les airs au dessus du lanceur. Au deuxième tour après canalisation, elle se fracasse au sol, soufflant les créatures dans un rayon de 20m, leur infligeant 60+3D12+3D6 dégâts obscurs.', 25, 0, '-100', false); - -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Projection spectrale I', 'Le lanceur canalise sa magie pour manifester les émotions négatives d\'un défunt à partir du Voile et les projeter sur une cible, infligeant 8D3+8 de dégâts.', 5, 0, '-20', false), -('Projection spectrale II', 'Le lanceur canalise sa magie pour manifester les émotions négatives de deux défunts à partir du Voile et les projeter sur une cible, infligeant 8D3+3D8+8 de dégâts.', 5, 0, '-40', false), -('Projection spectrale III', 'Le lanceur manifeste un esprit haineux à partir du Voile se jetant sur la cible, infligeant 8D8 de dégâts.', 5, 0, '-60', false), -('Force spectrale', 'Le lanceur ouvre un portail vers le Voile qui déverse un torrent d\'émotions négatives et de regrets sur une cible, lui infligeant 10D10 de dégâts. La cible doit également effectuer 3 jets de VOL. Pour chaque échec, elle est tétanisée et incapable d\'agir pendant un tour.', 20, 0, '-80', false), - -('Œil de Sergalée', 'Le lanceur utilise la mémoire magique afin de revivre les dernières secondes d\'une créature consciente décédée. Il doit cependant connaître le nom et le visage de la créature. L\'âme de la créature doit également être intacte pour que le sort se conclue.', 0, 0, '-15x', false), - -('Kerato I', 'Le lanceur ramine un cadavre à l\'aide de sa force magique pendant 2D2 tours, obéissant à sa volonté. Les stats du cadavre sont égales à celles qu\'il possédait de son vivant, avec un malus global de -20. Le cadavre est faible à la magie blanche et immunisé contre la magie noire. Le cadavre ne peut pas lancer de sorts.', 15, 0, '-x', false), -('Kerato II', 'Le lanceur ramine un cadavre à l\'aide de sa force magique pendant 2D3 tours, obéissant à sa volonté. Les stats du cadavre sont égales à celles qu\'il possédait de son vivant, avec un malus global de -10. Le cadavre est faible à la magie blanche et immunisé contre la magie noire. Le cadavre ne peut pas lancer de sorts.', 15, 0, '-x', false), -('Kerato III', 'Le lanceur ramine un cadavre à l\'aide de sa force magique pendant 2D4 tours, obéissant à sa volonté. Les stats du cadavre sont égales à celles qu\'il possédait de son vivant. Le cadavre est faible à la magie blanche et immunisé contre la magie noire. Le cadavre ne peut pas lancer de sorts.', 20, 0, '-x', false), -('Sang pourri', 'Le lanceur ramine un cadavre à l\'aide de sa force magique pendant 2D5 tours, obéissant à sa volonté. Les stats du cadavre sont égales à celles qu\'il possédait de son vivant, avec un bonus global de 10. Le cadavre est faible à la magie blanche et immunisé contre la magie noire. Le cadavre ne peut pas lancer de sorts.', 25, 0, '-x', false), - -('Mémoire de chair', 'Un cadavre animé sous le contrôle du lanceur regagne un aspect de son esprit, comme sa personnalité ou ses souvenirs, et s\'émancipe de la volonté du lanceur. Confère la capacité au cadavre de lancer des sorts. L\'âme de la créature doit également être intacte pour que le sort se conclue.', 15, 0, '?', false), - -('Putréfaction I', 'Le lanceur, au toucher d\'une créature, utilise sa magie pour accélérer temporairement le vieillissement de ses cellules, lui infligeant 1D6 dégâts nécrotiques et lui faisant perdre 1D8 PV max. La créature souffre également du statut "Fatigue I".', 10, 0, '-15', false), -('Putréfaction II', 'Le lanceur, au toucher d\'une créature, utilise sa magie pour accélérer temporairement le vieillissement de ses cellules, lui infligeant 1D8 dégâts nécrotiques et lui faisant perdre 1D10 PV max. La créature souffre également du statut "Fatigue II".', 15, 0, '-30', false), -('Putréfaction III', 'Le lanceur, au toucher d\'une créature, utilise sa magie pour accélérer temporairement le vieillissement de ses cellules, lui infligeant 1D10 dégâts nécrotiques et lui faisant perdre 1D12 PV max. La créature souffre également du statut "Fatigue III".', 15, 0, '-45', false), -('À travers les âges', 'Le lanceur, au toucher d\'une créature, utilise sa magie pour accélérer exponentiellement le vieillissement de ses cellules, lui infligeant 1D12 dégâts nécrotiques et lui faisant perdre 1D20 PV max. La créature souffre également du statut "Fatigue V".', 20, 1, '-60', false), - -('Évocation', 'Au cours d\'un rituel, le lanceur utilise son corps comme un réceptacle pour accueillir l\'âme d\'un défunt. Le lanceur est considéré comme sous l\'influence d\'un contrôle mental, et peut, s\'il le souhaite, effectuer un jet de VOL pour reprendre le contrôle de son corps. L\'esprit du défunt est alors renvoyé dans le Voile. L\'âme de la créature doit également être intacte pour que le sort se conclue. Le lanceur doit également connaître le nom et le visage de la personne.', 10, 0, -60, true), -('Dévocation', 'Le lanceur renvoit un esprit possèdant le corps d\'une créature dans le Voile.', 10, 0, '-x', false); - -INSERT INTO `spell` (name, description, level, charge, cost, is_ritual) VALUES -('Globules corrosives I', 'Une aura verte sombre se dégage des mains du lanceur. Une nuée de petites globules se manifestent de cette aura et fondent sur une cible unique, infligeant 1D10 de dégats de corrosion pendant 3 tours. Le sort ne peut se manifester dans un liquide.', 0, 0, '-10', false), -('Globules corrosives II', 'Une aura verte sombre se dégage des mains du lanceur. Une nuée de globules se manifestent de cette aura et fondent sur une cible unique, infligeant 2D10 de dégats de corrosion pendant 3 tours. Le sort ne peut se manifester dans un liquide.', 0, 0, '-30', false), -('Globules corrosives III', 'Une aura verte sombre se dégage des mains du lanceur. Une énorme nuée de globules se manifeste de cette aura et fond sur une cible unique, infligeant 3D10 de dégats de corrosion pendant 3 tours. Le sort ne peut se manifester dans un liquide.', 0, 0, '-50', false), -('Vent toxique', 'Le lanceur manifeste un courant d\'air mordant et nocif sur un petit groupe de cibles, infligeant 4D10 dégâts de corrosion pendant 3 tours à ces dernières.', 20, 1, '-70', false); - --- USERS -INSERT INTO `user` (name, mail, password) VALUES -('Kevin', '35.alexis.mail@gmail.com', 'sept777'); - --- INGREDIENTS -INSERT INTO `ingredient` (name, description) VALUES -('Volonté', 'La force de volonté du lanceur, concentrée sur un objectif'), -('Geste', 'Un geste précis facilitant la canalisation magique'); - --- VARIABLES -INSERT INTO `variable` (description) VALUES -('Nombre de personnes soignées'); - --- ASSOCIATIONS - SPELLS / SCHOOLS -/* -SCHEMA -(id_spell, id_school), - -*/ - -DELIMITER $$ -CREATE PROCEDURE insertIntoSchoolRange(IN delimiter_start INT, IN delimiter_end INT, IN id_school INT) -BEGIN - SET @i = delimiter_start; - WHILE @i <= delimiter_end DO - INSERT INTO spell_school (spell_id, school_id) VALUES (@i, id_school); - SET @i = @i + 1; - END WHILE; -END$$ -DELIMITER ; - -CALL insertIntoSchoolRange(1, 25, 1); -CALL insertIntoSchoolRange(26, 50, 2); -CALL insertIntoSchoolRange(51, 66, 3); -CALL insertIntoSchoolRange(67, 91, 4); -CALL insertIntoSchoolRange(92, 107, 5); -CALL insertIntoSchoolRange(108, 111, 6); diff --git a/database/auracle_db_schools.sql b/database/auracle_db_schools.sql new file mode 100644 index 0000000..c13e2c2 --- /dev/null +++ b/database/auracle_db_schools.sql @@ -0,0 +1,23 @@ +/* Insertions de masses */ +DELIMITER $$ +CREATE PROCEDURE insertIntoSchoolRange(IN delimiter_start INT, IN delimiter_end INT, IN id_school INT) +BEGIN + SET @i = delimiter_start; + WHILE @i <= delimiter_end DO + INSERT INTO spell_school (spell_id, school_id) VALUES (@i, id_school); + SET @i = @i + 1; + END WHILE; +END$$ +DELIMITER ; + +CALL insertIntoSchoolRange(1, 25, 1); +CALL insertIntoSchoolRange(26, 50, 2); +CALL insertIntoSchoolRange(51, 70, 3); +CALL insertIntoSchoolRange(71, 95, 4); +CALL insertIntoSchoolRange(96, 111, 5); +CALL insertIntoSchoolRange(112, 115, 6); +CALL insertIntoSchoolRange(116, 141, 7); +CALL insertIntoSchoolRange(142, 167, 8); +CALL insertIntoSchoolRange(168, 193, 9); +CALL insertIntoSchoolRange(194, 217, 10); + From 96d13ec6e9de8dd410033638b53629e5fed96c5f Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 22 Jun 2020 21:36:51 +0200 Subject: [PATCH 04/31] - Removed test data from db files, cleaned structures, and fix other things --- client/src/components/spells/spell-card.vue | 1 + database/auracle_db_create.sql | 2 - database/auracle_db_schools.sql | 14 +++- functions.js | 48 +++++++++++++ repositories/ingredient-repository.js | 29 ++------ repositories/school-repository.js | 29 ++------ repositories/spell-repository.js | 63 ++++++++++------ repositories/user-repository.js | 3 +- repositories/variable-repository.js | 29 ++------ routes/ingredients.js | 28 +------- routes/meta_schools.js | 29 +------- routes/schools.js | 28 +------- routes/spells.js | 79 ++++++++++++++------- routes/users.js | 3 - routes/variables.js | 28 +------- 15 files changed, 186 insertions(+), 227 deletions(-) create mode 100644 functions.js diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index 1bef45b..78cb59d 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -126,6 +126,7 @@ export default { @include colorschool(hydromancie,#3f68c7); @include colorschool(electromancie,#cd9731); @include colorschool(terramancie,#7e5540); + @include colorschool(sidéromancie,#58697a); @include colorschool(caelomancie,#a8a8a8); @include colorschool(légimancie,#5dbabd); @include colorschool(illusiomancie,#9f63a1); diff --git a/database/auracle_db_create.sql b/database/auracle_db_create.sql index fdbdb4b..79f45bd 100644 --- a/database/auracle_db_create.sql +++ b/database/auracle_db_create.sql @@ -114,8 +114,6 @@ BEGIN END$$ DELIMITER ; - - /* =========== PRIMARY INSERTS =========== */ SET NAMES utf8; USE auracle; diff --git a/database/auracle_db_schools.sql b/database/auracle_db_schools.sql index c13e2c2..07f9126 100644 --- a/database/auracle_db_schools.sql +++ b/database/auracle_db_schools.sql @@ -20,4 +20,16 @@ CALL insertIntoSchoolRange(116, 141, 7); CALL insertIntoSchoolRange(142, 167, 8); CALL insertIntoSchoolRange(168, 193, 9); CALL insertIntoSchoolRange(194, 217, 10); - +CALL insertIntoSchoolRange(218, 220, 11); +CALL insertIntoSchoolRange(221, 242, 12); +CALL insertIntoSchoolRange(243, 257, 13); +CALL insertIntoSchoolRange(258, 272, 14); +CALL insertIntoSchoolRange(273, 283, 15); +CALL insertIntoSchoolRange(284, 301, 16); +CALL insertIntoSchoolRange(302, 322, 17); +CALL insertIntoSchoolRange(323, 339, 19); +CALL insertIntoSchoolRange(340, 341, 20); +CALL insertIntoSchoolRange(342, 356, 21); +CALL insertIntoSchoolRange(357, 387, 22); +CALL insertIntoSchoolRange(388, 396, 24); +CALL insertIntoSchoolRange(397, 403, 25); diff --git a/functions.js b/functions.js new file mode 100644 index 0000000..2fbdb92 --- /dev/null +++ b/functions.js @@ -0,0 +1,48 @@ +// Error handling +const { HttpError } = require('./validations/Errors') + +const regexInt = RegExp(/^[1-9]\d*$/) +const regexXSS = RegExp(/<[^>]*script/) + +// Check if int for param validation +const paramIntCheck = (req, res, next, input) => { + try { + if (regexInt.test(input)) { + next() + } else { + throw new Error + } + } catch (err) { + err = new HttpError(403, 'Provided ID must be an integer and not zero') + res.status(err.code).send(JSON.stringify( + { + "error": err.message, + "code": err.code + }) + ) + } +} + +// Check if script injection attempt +const isXSSAttempt = (string) => { + if (regexXSS.test(string)) { + return true + } else { + return false + } +} + +// Check if object is null +const isEmptyObject = (obj) => { + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + return true + } else { + return false + } +} + +module.exports = { + paramIntCheck, + isXSSAttempt, + isEmptyObject +} \ No newline at end of file diff --git a/repositories/ingredient-repository.js b/repositories/ingredient-repository.js index ea226b4..e91aeb9 100644 --- a/repositories/ingredient-repository.js +++ b/repositories/ingredient-repository.js @@ -10,7 +10,8 @@ const IngredientValidation = require("../validations/IngredientValidation") v.addSchema(IngredientValidation, "/IngredientValidation") // Validations -const regexXSS = RegExp(/<[^>]*script/) +const isXSSAttempt = require('../functions').isXSSAttempt +const isEmptyObject = require('../functions').isEmptyObject // Error handling const { HttpError } = require('../validations/Errors') @@ -68,11 +69,11 @@ class IngredientRepository { addOne(igr) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(igr)) { + if (isEmptyObject(igr)) { reject(new HttpError(403, "Error: Ingredient cannot be nothing !")) } else if (!v.validate(igr, IngredientValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(igr, IngredientValidation).errors)) - } else if (this.isXSSAttempt(igr.description)) { + } else if (isXSSAttempt(igr.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { bookshelf.transaction(t => { @@ -103,11 +104,11 @@ class IngredientRepository { updateOne(id, igr) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(igr)) { + if (isEmptyObject(igr)) { reject(new HttpError(403, "Error: Ingredient cannot be nothing !")) } else if (!v.validate(igr, IngredientValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(igr, IngredientValidation).errors)) - } else if (this.isXSSAttempt(igr.description)) { + } else if (isXSSAttempt(igr.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { model.forge({id: id}) @@ -165,24 +166,6 @@ class IngredientRepository { }) }) } - - // Check if object is null - isEmptyObject(obj) { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } - } - - // Check if script injection attempt - isXSSAttempt(string) { - if (regexXSS.test(string)) { - return true - } else { - return false - } - } } module.exports = IngredientRepository \ No newline at end of file diff --git a/repositories/school-repository.js b/repositories/school-repository.js index f15d597..f9eae87 100644 --- a/repositories/school-repository.js +++ b/repositories/school-repository.js @@ -10,7 +10,8 @@ const SchoolValidation = require("../validations/SchoolValidation") v.addSchema(SchoolValidation, "/SchoolValidation") // Validations -const regexXSS = RegExp(/<[^>]*script/) +const isXSSAttempt = require('../functions').isXSSAttempt +const isEmptyObject = require('../functions').isEmptyObject // Error handling const { HttpError } = require('../validations/Errors') @@ -67,11 +68,11 @@ class SchoolRepository { addOne(s) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(s)) { + if (isEmptyObject(s)) { reject(new HttpError(403, "Error: School cannot be nothing !")) } else if (!v.validate(s, SchoolValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SchoolValidation).errors)) - } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description)) { + } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { bookshelf.transaction(t => { @@ -103,11 +104,11 @@ class SchoolRepository { updateOne(id, s) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(s)) { + if (isEmptyObject(s)) { reject(new HttpError(403, "Error: School cannot be nothing !")) } else if (!v.validate(s, SchoolValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SchoolValidation).errors)) - } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description)) { + } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { model.forge({id: id}) @@ -166,24 +167,6 @@ class SchoolRepository { }) }) } - - // Check if object is null - isEmptyObject(obj) { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } - } - - // Check if script injection attempt - isXSSAttempt(string) { - if (regexXSS.test(string)) { - return true - } else { - return false - } - } } module.exports = SchoolRepository \ No newline at end of file diff --git a/repositories/spell-repository.js b/repositories/spell-repository.js index b376e96..f694fde 100644 --- a/repositories/spell-repository.js +++ b/repositories/spell-repository.js @@ -10,7 +10,8 @@ const SpellValidation = require("../validations/SpellValidation") v.addSchema(SpellValidation, "/SpellValidation") // Validations -const regexXSS = RegExp(/<[^>]*script/) +const isXSSAttempt = require('../functions').isXSSAttempt +const isEmptyObject = require('../functions').isEmptyObject // Error handling const { HttpError } = require('../validations/Errors') @@ -34,6 +35,40 @@ class SpellRepository { }) } + getAllPublic() { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'public' : 1 }) + .fetchAll({ withRelated: ['schools.meta_schools', 'variables', 'ingredients'] }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get public spells")) + }) + }) + } + + getPage(page) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'public' : 1 }) + .fetchPage({ + pageSize: 20, + page: page, + withRelated: ['schools.meta_schools', 'variables', 'ingredients'], + }) + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + console.log(err) + reject(new HttpError(500, "Couldn't get public spells")) + }) + }) + } + getOne(id) { return new Promise((resolve, reject) => { model.forge() @@ -52,11 +87,11 @@ class SpellRepository { addOne(s) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(s)) { + if (isEmptyObject(s)) { reject(new HttpError(403, "Error: Spell cannot be nothing !")) } else if (!v.validate(s, SpellValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SpellValidation).errors)) - } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description) || this.isXSSAttempt(s.cost)) { + } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { bookshelf.transaction(t => { @@ -112,11 +147,11 @@ class SpellRepository { updateOne(id, s) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(s)) { + if (isEmptyObject(s)) { reject(new HttpError(403, "Error: Spell cannot be nothing !")) } else if (!v.validate(s, SpellValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(s, SpellValidation).errors)) - } else if (this.isXSSAttempt(s.name) || this.isXSSAttempt(s.description) || this.isXSSAttempt(s.cost)) { + } else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { model.forge({id: id}) @@ -222,24 +257,6 @@ class SpellRepository { }) }) } - - // Check if object is null - isEmptyObject(obj) { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } - } - - // Check if script injection attempt - isXSSAttempt(string) { - if (regexXSS.test(string)) { - return true - } else { - return false - } - } } module.exports = SpellRepository \ No newline at end of file diff --git a/repositories/user-repository.js b/repositories/user-repository.js index edf866a..3b77786 100644 --- a/repositories/user-repository.js +++ b/repositories/user-repository.js @@ -13,7 +13,8 @@ const UserValidation = require("../validations/UserValidation") v.addSchema(UserValidation, "/UserValidation") // Validations -const regexXSS = RegExp(/<[^>]*script/) +const isXSSAttempt = require('../functions').isXSSAttempt +const isEmptyObject = require('../functions').isEmptyObject // Error handling const { HttpError } = require('../validations/Errors') diff --git a/repositories/variable-repository.js b/repositories/variable-repository.js index 57bb530..2fc2a31 100644 --- a/repositories/variable-repository.js +++ b/repositories/variable-repository.js @@ -10,7 +10,8 @@ const VariableValidation = require("../validations/VariableValidation") v.addSchema(VariableValidation, "/VariableValidation") // Validations -const regexXSS = RegExp(/<[^>]*script/) +const isXSSAttempt = require('../functions').isXSSAttempt +const isEmptyObject = require('../functions').isEmptyObject // Error handling const { HttpError } = require('../validations/Errors') @@ -67,11 +68,11 @@ class VariableRepository { addOne(vr) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(vr)) { + if (isEmptyObject(vr)) { reject(new HttpError(403, "Error: Variable cannot be nothing !")) } else if (!v.validate(vr, VariableValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(vr, VariableValidation).errors)) - } else if (this.isXSSAttempt(vr.description)) { + } else if (isXSSAttempt(vr.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { bookshelf.transaction(t => { @@ -101,11 +102,11 @@ class VariableRepository { updateOne(id, vr) { return new Promise((resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't - if (this.isEmptyObject(vr)) { + if (isEmptyObject(vr)) { reject(new HttpError(403, "Error: Variable cannot be nothing !")) } else if (!v.validate(vr, VariableValidation).valid) { reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(vr, VariableValidation).errors)) - } else if (this.isXSSAttempt(vr.description)) { + } else if (isXSSAttempt(vr.description)) { reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) } else { model.forge({id: id}) @@ -162,24 +163,6 @@ class VariableRepository { }) }) } - - // Check if object is null - isEmptyObject(obj) { - if (Object.keys(obj).length === 0 && obj.constructor === Object) { - return true - } else { - return false - } - } - - // Check if script injection attempt - isXSSAttempt(string) { - if (regexXSS.test(string)) { - return true - } else { - return false - } - } } module.exports = VariableRepository \ No newline at end of file diff --git a/routes/ingredients.js b/routes/ingredients.js index 7748a8e..e51c348 100644 --- a/routes/ingredients.js +++ b/routes/ingredients.js @@ -6,17 +6,12 @@ let router = express.Router() // Connection const connection = require('../database/bookshelf') -const db = connection.db +const functions = require('../functions') // Repository const IngredientRepository = require('../repositories/ingredient-repository'); const Ingredients = new IngredientRepository(); -const regexInt = RegExp(/^[1-9]\d*$/) - -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES // GET ALL ------------------ const getIngredients = () => { @@ -167,24 +162,7 @@ router.delete('/:id/', async (req, res) => { }) }) -// Param validation for ID -// (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - throw new Error; - } - } catch (err) { - err = new HttpError(403, 'Provided ID must be an integer and not zero') - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - } -}) +// Param validations +router.param('id', functions.paramIntCheck) module.exports = router \ No newline at end of file diff --git a/routes/meta_schools.js b/routes/meta_schools.js index 4639c36..8812891 100644 --- a/routes/meta_schools.js +++ b/routes/meta_schools.js @@ -6,17 +6,12 @@ let router = express.Router() // Connection const connection = require('../database/bookshelf') -const db = connection.db +const functions = require('../functions') // Repository const MetaSchoolRepository = require('../repositories/meta-school-repository'); const MetaSchools = new MetaSchoolRepository(); -const regexInt = RegExp(/^[1-9]\d*$/) - -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES // GET ALL ------------------ const getMetaSchools = () => { @@ -67,25 +62,7 @@ router.get('/:id/', async (req, res) => { }) }) - -// Param validation for ID -// (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - throw new Error; - } - } catch (err) { - err = new HttpError(403, 'Provided ID must be an integer and not zero') - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - } -}) +// Param validations +router.param('id', functions.paramIntCheck) module.exports = router \ No newline at end of file diff --git a/routes/schools.js b/routes/schools.js index 1be0200..173af9c 100644 --- a/routes/schools.js +++ b/routes/schools.js @@ -6,17 +6,12 @@ let router = express.Router() // Connection const connection = require('../database/bookshelf') -const db = connection.db +const functions = require('../functions') // Repository const SchoolRepository = require('../repositories/school-repository'); const Schools = new SchoolRepository(); -const regexInt = RegExp(/^[1-9]\d*$/) - -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES // GET ALL ------------------ const getSchools = () => { @@ -166,24 +161,7 @@ router.delete('/:id/', async (req, res) => { }) }) -// Param validation for ID -// (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - throw new Error; - } - } catch (err) { - err = new HttpError(403, 'Provided ID must be an integer and not zero') - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - } -}) +// Param validations +router.param('id', functions.paramIntCheck) module.exports = router \ No newline at end of file diff --git a/routes/spells.js b/routes/spells.js index 2d3ea4f..f0acaf0 100644 --- a/routes/spells.js +++ b/routes/spells.js @@ -6,18 +6,37 @@ let router = express.Router() // Connection const connection = require('../database/bookshelf') -const db = connection.db +const functions = require('../functions') // Repository const SpellReposity = require('../repositories/spell-repository'); const Spells = new SpellReposity(); -const regexInt = RegExp(/^[1-9]\d*$/) - -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES +// GET ALL PUBLIC ------------------ +const getPublicSpells = () => { + return Spells.getAllPublic() + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/', async (req, res) => { + getPublicSpells() + .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 + }) + ) + }) +}) + // GET ALL ------------------ const getSpells = () => { return Spells.getAll() @@ -26,7 +45,7 @@ const getSpells = () => { throw err }) } -router.get('/', async (req, res) => { +router.get('/private', async (req, res) => { getSpells() .then(v => { res.setHeader('Content-Type', 'application/json;charset=utf-8') @@ -42,6 +61,29 @@ router.get('/', async (req, res) => { }) }) +// GET SOME ------------------ +const getSomeSpells = (page) => { + return Spells.getPage(page) + .catch(err => { + console.log(err) + throw err + }) +} +router.get('/page/:page', async (req, res) => { + getSomeSpells(req.params.page) + .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 + }) + ) + }) +}) // GET ONE ------------------ const getSpell = (id) => { @@ -142,25 +184,8 @@ router.delete('/:id/', async (req, res) => { }) }) - -// Param validation for ID - // (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - throw new Error; - } - } catch (err) { - err = new HttpError(403, 'Provided ID must be an integer and not zero') - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - } -}) +// Param validations +router.param('id', functions.paramIntCheck) +router.param('page', functions.paramIntCheck) module.exports = router diff --git a/routes/users.js b/routes/users.js index 951aab9..2060af6 100644 --- a/routes/users.js +++ b/routes/users.js @@ -14,9 +14,6 @@ const Users = new UserRepository(); const regexInt = RegExp(/^[1-9]\d*$/) -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES // GET ALL ------------------ const getUsers = () => { diff --git a/routes/variables.js b/routes/variables.js index 01ee961..15bfa39 100644 --- a/routes/variables.js +++ b/routes/variables.js @@ -6,17 +6,12 @@ let router = express.Router() // Connection const connection = require('../database/bookshelf') -const db = connection.db +const functions = require('../functions') // Repository const VariableRepository = require('../repositories/variable-repository'); const Variables = new VariableRepository(); -const regexInt = RegExp(/^[1-9]\d*$/) - -// Error handling -const { HttpError } = require('../validations/Errors') - // ROUTES // GET ALL ------------------ const getvariables = () => { @@ -167,24 +162,7 @@ router.delete('/:id/', async (req, res) => { }) }) -// Param validation for ID -// (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - throw new Error; - } - } catch (err) { - err = new HttpError(403, 'Provided ID must be an integer and not zero') - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - } -}) +// Param validations +router.param('id', functions.paramIntCheck) module.exports = router \ No newline at end of file From 7819cf004d5e670ecea800b4a52dd5e4ad6bd3ab Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 22 Jun 2020 23:37:24 +0200 Subject: [PATCH 05/31] - dear god lazy loading why but it works good night --- client/src/api/spellsRepository.js | 13 ++- .../src/components/spells/add-spell-card.vue | 2 +- .../src/components/spells/edit-spell-card.vue | 2 +- client/src/components/spells/spell-card.vue | 2 +- client/src/components/spells/spells-list.vue | 101 ++++++++++++++---- 5 files changed, 90 insertions(+), 30 deletions(-) diff --git a/client/src/api/spellsRepository.js b/client/src/api/spellsRepository.js index 5640688..becb817 100644 --- a/client/src/api/spellsRepository.js +++ b/client/src/api/spellsRepository.js @@ -5,19 +5,22 @@ const resource = "/spells" // CRUD methods for spells export default { - getSpells() { + getAll() { return api.get(`${resource}`) }, - getSpell(id) { + getPage(page) { + return api.get(`${resource}/page/${page}`) + }, + getOne(id) { return api.get(`${resource}/${id}`) }, - addSpell(data) { + addOne(data) { return api.post(`${resource}`, data) }, - updateSpell(id, data) { + updateOne(id, data) { return api.put(`${resource}/${id}`, data) }, - deleteSpell(id) { + deleteOne(id) { return api.delete(`${resource}/${id}`) } } \ No newline at end of file diff --git a/client/src/components/spells/add-spell-card.vue b/client/src/components/spells/add-spell-card.vue index 94141f5..353bbc5 100644 --- a/client/src/components/spells/add-spell-card.vue +++ b/client/src/components/spells/add-spell-card.vue @@ -143,7 +143,7 @@ export default { ingredients: ingredientsData, } - Spells.addSpell(data) + Spells.addOne(data) .then(v => { this.$emit('addSpell', v.data) this.$refs["add_spell_modal"].hide() diff --git a/client/src/components/spells/edit-spell-card.vue b/client/src/components/spells/edit-spell-card.vue index fbf451f..0203b9e 100644 --- a/client/src/components/spells/edit-spell-card.vue +++ b/client/src/components/spells/edit-spell-card.vue @@ -182,7 +182,7 @@ export default { ingredients: ingredientsData, } - Spells.updateSpell(this.spell.id, data) + Spells.updateOne(this.spell.id, data) .then(v => { this.$emit('updateSpell', v.data) }) diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index 78cb59d..27bbbae 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -93,7 +93,7 @@ export default { this.$emit('editSpell', spell) }, deleteSpell(spell) { - Spells.deleteSpell(this.spell.id) + Spells.deleteOne(this.spell.id) .then(() => { this.$emit('deleteSpell', spell) }) diff --git a/client/src/components/spells/spells-list.vue b/client/src/components/spells/spells-list.vue index 74e0522..3c84d7b 100644 --- a/client/src/components/spells/spells-list.vue +++ b/client/src/components/spells/spells-list.vue @@ -4,11 +4,35 @@ add Ajouter un sort -
- +
+
+ +
+ + + +
- -
@@ -21,7 +45,7 @@ import AddSpellCard from "./add-spell-card" // API import { RepositoryFactory } from "~/api/repositories" const Spells = RepositoryFactory.get('spells') -const Schools = RepositoryFactory.get('schools') +// const Schools = RepositoryFactory.get('schools') export default { name: 'spellslist', @@ -31,34 +55,67 @@ export default { 'add-spell-card': AddSpellCard, }, props: { - school_id: String + school_id: String, }, data() { return { - loading: false, spells: [], + loading: false, current_edit_spell: {}, + currentIndex: 1, adding_spell: false, } }, - created() { - this.computeSpells() + computed: { + computedSpells() { + return this.spells + } + }, + beforeMount() { + this.spells = this.computedSpells + this.getInitialSpells() + }, + mounted() { + this.scroll() }, methods: { - async fetchSpells() { - if (!this.school_id) { - const { data } = await Spells.getSpells() - return data - } else { - const { data } = await Schools.getSpellsFromSchool(this.school_id) - return data.spells - } + getInitialSpells() { + Spells.getPage(this.currentIndex) + .then(v => { + this.loading = true + let spells = this.computedSpells + spells.push(v.data) + this.spells = spells[0] + }) + .then(() => { + this.currentIndex++ + this.loading = false + }) + .catch(err => { + console.log(err) + }) }, - async computeSpells() { - this.loading = true - const displaySpells = await this.fetchSpells() - this.loading = false - this.spells = displaySpells + scroll() { + window.onscroll = () => { + if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + Spells.getPage(this.currentIndex) + .then(v => { + this.loading = true + let spells = this.computedSpells + for (let i = 0; i < v.data.length; i++) { + const element = v.data[i]; + spells.push(element) + } + }) + .then(() => { + this.currentIndex++ + this.loading = false + }) + .catch(err => { + console.log(err) + }) + } + } }, editSpell(e) { this.current_edit_spell = e; From 52a7348d7eaee18add1b8b486e1ce9d2040db83f Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Tue, 23 Jun 2020 21:45:58 +0200 Subject: [PATCH 06/31] - added search to spells list --- client/src/components/spells/spells-list.vue | 35 ++++++++++++++++++-- client/src/pages/spells-page.vue | 29 ---------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/client/src/components/spells/spells-list.vue b/client/src/components/spells/spells-list.vue index 3c84d7b..33f0e60 100644 --- a/client/src/components/spells/spells-list.vue +++ b/client/src/components/spells/spells-list.vue @@ -1,5 +1,34 @@ @@ -74,7 +79,6 @@ import AddSpellCard from "./add-spell-card" // API import { RepositoryFactory } from "~/api/repositories" const Spells = RepositoryFactory.get('spells') -// const Schools = RepositoryFactory.get('schools') export default { name: 'spellslist', @@ -184,5 +188,8 @@ export default { \ No newline at end of file diff --git a/client/src/global-components.js b/client/src/global-components.js new file mode 100644 index 0000000..fc988cb --- /dev/null +++ b/client/src/global-components.js @@ -0,0 +1,7 @@ +import Navbar from './components/global/navbar/navbar' +import Loader from './components/global/loader' + +export default [ + Navbar, + Loader +] \ No newline at end of file diff --git a/client/src/main.js b/client/src/main.js index db0cc12..9f46591 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -3,38 +3,36 @@ import Vue from 'vue' import VueRouter from 'vue-router' import App from './app.vue' +import Globals from './global-components.js' +Globals.forEach(component => { + Vue.component(component.name, component) +}); + // Auth require('dotenv').config() -// Router -import routes from './routes' -Vue.use(VueRouter) - // Jquery import jquery from 'jquery' window.$ = jquery window.jquery = jquery -// Global styles +// Styles import './assets/scss/_global.scss' - -// Bootstrap import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' import 'bootstrap/dist/js/bootstrap.js' + +// Plugins import { BootstrapVue } from 'bootstrap-vue' Vue.use(BootstrapVue) -// Masonry import { VueMasonryPlugin } from 'vue-masonry'; Vue.use(VueMasonryPlugin) -// Clipboard plugin import clipboard from 'v-clipboard' Vue.use(clipboard) -Vue.config.productionTip = false - +// FUNCTIONS var filter = function(text, length, clamp){ clamp = clamp || '...'; var node = document.createElement('div'); @@ -44,6 +42,9 @@ var filter = function(text, length, clamp){ }; Vue.filter('truncate', filter); +// Router +import routes from './routes' +Vue.use(VueRouter) const router = new VueRouter({ mode: 'history', routes, @@ -51,9 +52,9 @@ const router = new VueRouter({ linkExactActiveClass: "active", }); +// Mount Vue const app = new Vue({ render: h => h(App), router }) - app.$mount('#srs') From f8a1a9e73f93dbfb5d3cb3811f2b4fe4c272a3bb Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 28 Jun 2020 23:13:47 +0200 Subject: [PATCH 08/31] - Fixed scroll trigger and error message --- client/src/components/spells/spells-list.vue | 5 +++-- repositories/school-repository.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/components/spells/spells-list.vue b/client/src/components/spells/spells-list.vue index fc95577..d177a1b 100644 --- a/client/src/components/spells/spells-list.vue +++ b/client/src/components/spells/spells-list.vue @@ -39,7 +39,7 @@
{ - if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { + if (((window.innerHeight + window.scrollY) - document.body.offsetHeight) >= -1) { Spells.getPage(this.currentIndex) .then(v => { this.loading = true @@ -160,6 +160,7 @@ export default { cancelAdd() { this.adding_spell = false }, + // Receives events to update the data addSpell(e) { Spells.getOne(e.id) .then(v => { diff --git a/repositories/school-repository.js b/repositories/school-repository.js index f9eae87..0aef22b 100644 --- a/repositories/school-repository.js +++ b/repositories/school-repository.js @@ -60,7 +60,7 @@ class SchoolRepository { }) .catch(err => { console.log(err) - reject(new HttpError(500, "Couldn't get school")) + reject(new HttpError(500, "Couldn't get spells from school")) }) }) } From 4e04014b326aea7c8de121ad205cacad15eecaf2 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 29 Jun 2020 15:55:37 +0200 Subject: [PATCH 09/31] - Fixed some typos --- client/src/api/ingredientsRepository.js | 2 -- client/src/api/metaschoolsRepository.js | 2 -- client/src/api/schoolsRepository.js | 9 ++------- client/src/api/spellsRepository.js | 2 -- client/src/api/variablesRepository.js | 2 -- client/src/pages/schools/single-school-page.vue | 2 +- 6 files changed, 3 insertions(+), 16 deletions(-) diff --git a/client/src/api/ingredientsRepository.js b/client/src/api/ingredientsRepository.js index ab63ca7..fa4b013 100644 --- a/client/src/api/ingredientsRepository.js +++ b/client/src/api/ingredientsRepository.js @@ -1,9 +1,7 @@ import api from './api' -// URL for spells const resource = "/ingredients" -// CRUD methods for spells export default { getIngredients() { return api.get(`${resource}`) diff --git a/client/src/api/metaschoolsRepository.js b/client/src/api/metaschoolsRepository.js index 7d8d018..07aeb6b 100644 --- a/client/src/api/metaschoolsRepository.js +++ b/client/src/api/metaschoolsRepository.js @@ -1,9 +1,7 @@ import api from './api' -// URL for spells const resource = "/meta_schools" -// CRUD methods for spells export default { getMetaSchools() { return api.get(`${resource}`) diff --git a/client/src/api/schoolsRepository.js b/client/src/api/schoolsRepository.js index 6c33e11..fada229 100644 --- a/client/src/api/schoolsRepository.js +++ b/client/src/api/schoolsRepository.js @@ -1,17 +1,12 @@ import api from './api' -// URL for spells const resource = "/schools" -// CRUD methods for spells export default { - getSchools() { + getOne() { return api.get(`${resource}`) }, - getSchool(id) { + getAll(id) { return api.get(`${resource}/${id}`) - }, - getSpellsFromSchool(id) { - return api.get(`${resource}/${id}/spells`) } } \ No newline at end of file diff --git a/client/src/api/spellsRepository.js b/client/src/api/spellsRepository.js index becb817..bcc4773 100644 --- a/client/src/api/spellsRepository.js +++ b/client/src/api/spellsRepository.js @@ -1,9 +1,7 @@ import api from './api' -// URL for spells const resource = "/spells" -// CRUD methods for spells export default { getAll() { return api.get(`${resource}`) diff --git a/client/src/api/variablesRepository.js b/client/src/api/variablesRepository.js index ec91f56..391a4f3 100644 --- a/client/src/api/variablesRepository.js +++ b/client/src/api/variablesRepository.js @@ -1,9 +1,7 @@ import api from './api' -// URL for spells const resource = "/variables" -// CRUD methods for spells export default { getVariables() { return api.get(`${resource}`) diff --git a/client/src/pages/schools/single-school-page.vue b/client/src/pages/schools/single-school-page.vue index 2bd0947..6681379 100644 --- a/client/src/pages/schools/single-school-page.vue +++ b/client/src/pages/schools/single-school-page.vue @@ -30,7 +30,7 @@ export default { }, methods: { async fetchSchool(id) { - const { data } = await Schools.getSchool(id) + const { data } = await Schools.getOne(id) return data }, async computeSchool() { From 60c179f35712582d1b86bb74693d35625a00efed Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 29 Jun 2020 16:02:14 +0200 Subject: [PATCH 10/31] - Fixed an API call --- client/src/api/schoolsRepository.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/api/schoolsRepository.js b/client/src/api/schoolsRepository.js index fada229..62ea04b 100644 --- a/client/src/api/schoolsRepository.js +++ b/client/src/api/schoolsRepository.js @@ -3,10 +3,10 @@ import api from './api' const resource = "/schools" export default { - getOne() { + getAll() { return api.get(`${resource}`) }, - getAll(id) { + getOne(id) { return api.get(`${resource}/${id}`) } } \ No newline at end of file From 293451288d6e755d4b414e5fbae9ed41efa2c733 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 29 Jun 2020 16:18:26 +0200 Subject: [PATCH 11/31] - Fixed methods of spell list --- client/src/api/schoolsRepository.js | 3 +++ client/src/components/spells/spells-list.vue | 27 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/client/src/api/schoolsRepository.js b/client/src/api/schoolsRepository.js index 62ea04b..dd0529f 100644 --- a/client/src/api/schoolsRepository.js +++ b/client/src/api/schoolsRepository.js @@ -8,5 +8,8 @@ export default { }, getOne(id) { return api.get(`${resource}/${id}`) + }, + getSpellsFromOne(id) { + return api.get(`${resource}/${id}/spells`) } } \ No newline at end of file diff --git a/client/src/components/spells/spells-list.vue b/client/src/components/spells/spells-list.vue index d177a1b..4c8d047 100644 --- a/client/src/components/spells/spells-list.vue +++ b/client/src/components/spells/spells-list.vue @@ -79,6 +79,7 @@ import AddSpellCard from "./add-spell-card" // API import { RepositoryFactory } from "~/api/repositories" const Spells = RepositoryFactory.get('spells') +const Schools = RepositoryFactory.get('schools') export default { name: 'spellslist', @@ -107,10 +108,16 @@ export default { }, beforeMount() { this.spells = this.computedSpells - this.getInitialSpells() + if (!this.school_id) { + this.getInitialSpells() + } else { + this.getInitialSchoolSpells() + } }, mounted() { - this.scroll() + if (!this.school_id) { + this.scroll() + } }, methods: { getInitialSpells() { @@ -129,6 +136,22 @@ export default { console.log(err) }) }, + getInitialSchoolSpells() { + Schools.getSpellsFromOne(this.school_id) + .then(v => { + this.loading = true + let spells = this.computedSpells + spells.push(v.data.spells) + this.spells = spells[0] + }) + .then(() => { + this.currentIndex++ + this.loading = false + }) + .catch(err => { + console.log(err) + }) + }, scroll() { window.onscroll = () => { if (((window.innerHeight + window.scrollY) - document.body.offsetHeight) >= -1) { From 9abf084530ba8b18710cd59bce6de50c3013c9d7 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:05:21 +0200 Subject: [PATCH 12/31] - Reworded api calls --- client/src/api/ingredientsRepository.js | 4 ++-- client/src/api/metaschoolsRepository.js | 4 ++-- client/src/api/variablesRepository.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/api/ingredientsRepository.js b/client/src/api/ingredientsRepository.js index fa4b013..1b51667 100644 --- a/client/src/api/ingredientsRepository.js +++ b/client/src/api/ingredientsRepository.js @@ -3,10 +3,10 @@ import api from './api' const resource = "/ingredients" export default { - getIngredients() { + getAll() { return api.get(`${resource}`) }, - getIngredient(id) { + getOne(id) { return api.get(`${resource}/${id}`) }, } \ No newline at end of file diff --git a/client/src/api/metaschoolsRepository.js b/client/src/api/metaschoolsRepository.js index 07aeb6b..1f4985d 100644 --- a/client/src/api/metaschoolsRepository.js +++ b/client/src/api/metaschoolsRepository.js @@ -3,10 +3,10 @@ import api from './api' const resource = "/meta_schools" export default { - getMetaSchools() { + getAll() { return api.get(`${resource}`) }, - getMetaSchool(id) { + getOne(id) { return api.get(`${resource}/${id}`) }, } \ No newline at end of file diff --git a/client/src/api/variablesRepository.js b/client/src/api/variablesRepository.js index 391a4f3..9cb9c1d 100644 --- a/client/src/api/variablesRepository.js +++ b/client/src/api/variablesRepository.js @@ -3,10 +3,10 @@ import api from './api' const resource = "/variables" export default { - getVariables() { + getAll() { return api.get(`${resource}`) }, - getVariable(id) { + getOne(id) { return api.get(`${resource}/${id}`) }, } \ No newline at end of file From 53eaf57ab69d8a3acb811dfce38caab3de71b4c9 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:05:34 +0200 Subject: [PATCH 13/31] - Remodeled user db --- database/auracle_db_create.sql | 15 +++++++++------ database/auracle_db_schools.sql | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/database/auracle_db_create.sql b/database/auracle_db_create.sql index 79f45bd..221d642 100644 --- a/database/auracle_db_create.sql +++ b/database/auracle_db_create.sql @@ -15,8 +15,11 @@ CREATE TABLE IF NOT EXISTS `role` ( /* USERS */ CREATE TABLE IF NOT EXISTS `user` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(255) NOT NULL DEFAULT "Disciple", `mail` VARCHAR(255) NOT NULL, + `avatar` VARCHAR(255), + `gender` VARCHAR(255), `password` VARCHAR(255) NOT NULL, `role_id` INT UNSIGNED NOT NULL DEFAULT 1, `verified` BOOLEAN DEFAULT false, @@ -120,14 +123,14 @@ USE auracle; -- PERMISSIONS INSERT INTO `role` (name, description) VALUES -('Visiteur', "Utilisateur normal, peut consulter les sorts."), -('Scribe', "Gardiens des écrits, est capable de modifier et d'ajouter des sorts."), -('Arcanologue', "Maîtres de l'arcane, ils ont le pouvoir et la responsabilité de juger les sortilèges récents et de les supprimer, ou valider."), -('Augure', "Régents des grimoires, ils ont droit d'accès à l'intégralité des informations connues, et pouvoir absolu sur le savoir arcanique."); +("Visiteur", "Utilisateur normal, peut consulter les sorts."), +("Scribe", "Gardiens des écrits, les scribes sont capables de modifier et d'ajouter des sortilèges."), +("Arcanologue", "Maîtres de l'arcane, ils ont le pouvoir et la responsabilité de juger les sortilèges récents et de les supprimer, ou valider."), +("Augure", "Régents des grimoires, ils ont droit d'accès à l'intégralité des informations connues, et pouvoir absolu sur le savoir arcanique."); -- USERS -INSERT INTO `user` (name, mail, password, role_id) VALUES -('Izàc Tymos', 'tymos@ambrose.edu', 'root', 4); +INSERT INTO `user` (uuid, name, mail, password, role_id) VALUES +("6af978f0-96ed-11e8-bb38-37f5ae311cf6", "Izàc Tymos", "tymos@ambrose.edu", "root", 4); -- META SCHOOLS INSERT INTO `meta_school` (name, description) VALUES diff --git a/database/auracle_db_schools.sql b/database/auracle_db_schools.sql index 07f9126..ef0b0c0 100644 --- a/database/auracle_db_schools.sql +++ b/database/auracle_db_schools.sql @@ -1,3 +1,5 @@ +USE auracle; + /* Insertions de masses */ DELIMITER $$ CREATE PROCEDURE insertIntoSchoolRange(IN delimiter_start INT, IN delimiter_end INT, IN id_school INT) From cd1951fde027c44322d202b35cd44a877673c773 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:05:47 +0200 Subject: [PATCH 14/31] - Hid some tables for users --- models/user-model.js | 1 + 1 file changed, 1 insertion(+) diff --git a/models/user-model.js b/models/user-model.js index 60b5c64..9d7c019 100644 --- a/models/user-model.js +++ b/models/user-model.js @@ -3,6 +3,7 @@ const bookshelf = require('../database/bookshelf').bookshelf let User = bookshelf.Model.extend({ tableName: 'user', + hidden: ['id', 'password'] }) module.exports = bookshelf.model('User', User) \ No newline at end of file From 0101fb8a849c9899d1d32567f4cd6c311516df67 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:06:08 +0200 Subject: [PATCH 15/31] - Added UUID package --- package-lock.json | 11 ++++++++--- package.json | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d128861..05b8501 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1287,6 +1287,11 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" } } }, @@ -2376,9 +2381,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" }, "v8flags": { "version": "3.1.3", diff --git a/package.json b/package.json index f707d85..0e4bf54 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "jsonwebtoken": "^8.5.1", "knex": "^0.21.1", "morgan": "^1.10.0", - "mysql": "^2.18.1" + "mysql": "^2.18.1", + "uuid": "^8.2.0" } } From 939e384722457996cf7d1663e2c971a35b182492 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:06:21 +0200 Subject: [PATCH 16/31] - Fixed some api calls --- client/src/components/spells/add-spell-card.vue | 6 +++--- client/src/components/spells/edit-spell-card.vue | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/components/spells/add-spell-card.vue b/client/src/components/spells/add-spell-card.vue index 353bbc5..e260dcf 100644 --- a/client/src/components/spells/add-spell-card.vue +++ b/client/src/components/spells/add-spell-card.vue @@ -103,9 +103,9 @@ export default { }, created() { // Gets all relevant info for multiple selects - let fetchSchools = Schools.getSchools() - let fetchVariables = Variables.getVariables() - let fetchIngredients = Ingredients.getIngredients() + let fetchSchools = Schools.getAll() + let fetchVariables = Variables.getAll() + let fetchIngredients = Ingredients.getAll() Promise.all([fetchSchools, fetchVariables, fetchIngredients]) .then(v => { diff --git a/client/src/components/spells/edit-spell-card.vue b/client/src/components/spells/edit-spell-card.vue index 0203b9e..9806c20 100644 --- a/client/src/components/spells/edit-spell-card.vue +++ b/client/src/components/spells/edit-spell-card.vue @@ -132,9 +132,9 @@ export default { }, created() { // Gets all relevant info for multiple selects - let fetchSchools = Schools.getSchools() - let fetchVariables = Variables.getVariables() - let fetchIngredients = Ingredients.getIngredients() + let fetchSchools = Schools.getAll() + let fetchVariables = Variables.getAll() + let fetchIngredients = Ingredients.getAll() Promise.all([fetchSchools, fetchVariables, fetchIngredients]) .then(v => { From 3f82b487dc0d607474e5370e3416b3e3e41ee248 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Thu, 2 Jul 2020 23:06:55 +0200 Subject: [PATCH 17/31] - Started working on User routes and functions --- repositories/user-repository.js | 42 ++++++++++-- routes/users.js | 115 +++----------------------------- validations/UserValidation.js | 1 - 3 files changed, 46 insertions(+), 112 deletions(-) diff --git a/repositories/user-repository.js b/repositories/user-repository.js index 3b77786..3e44083 100644 --- a/repositories/user-repository.js +++ b/repositories/user-repository.js @@ -5,6 +5,7 @@ const model = require('../models/user-model') // Hashing and passwords const bcrypt = require('bcrypt') +const { v4: uuidv4 } = require('uuid') // Model validation const Validator = require('jsonschema').Validator @@ -26,7 +27,7 @@ class UserRepository { getAll() { return new Promise((resolve, reject) => { - this._model.forge() + model.forge() .fetchAll() .then(v => { resolve(v.toJSON({ omitPivot: true })) @@ -38,10 +39,10 @@ class UserRepository { }) } - getOne(id) { + getOneFromUUID(uuid) { return new Promise((resolve, reject) => { - this._model.forge() - .where({ 'id' : id }) + model.forge() + .where({ 'uuid' : uuid }) .fetch() .then(v => { resolve(v.toJSON({ omitPivot: true })) @@ -52,6 +53,39 @@ class UserRepository { }) }) } + + addOne(u) { + return new Promise(async (resolve, reject) => { + // Checks if body exists and if the model fits, and throws errors if it doesn't + if (isEmptyObject(u)) { + reject(new HttpError(403, "Error: User cannot be nothing !")) + } else if (!v.validate(u, UserValidation).valid) { + reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(u, UserValidation).errors)) + } else if (isXSSAttempt(u.name) || isXSSAttempt(u.password) || isXSSAttempt(u.mail)) { + reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + } else { + let hash = await bcrypt.hash(u.password, 10) + let uuid = uuidv4() + + // Needs to account for duplicate emails + bookshelf.transaction(t => { + return model.forge({ + 'uuid': uuid, + 'name': u.name, + 'mail': u.mail, + 'password': hash, + }) + .save(null, { + transacting: t + }) + .catch(err => { + console.log(err) + }) + }) + + } + }) + } } module.exports = UserRepository \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index 2060af6..427d801 100644 --- a/routes/users.js +++ b/routes/users.js @@ -12,8 +12,6 @@ const db = connection.db const UserRepository = require('../repositories/user-repository'); const Users = new UserRepository(); -const regexInt = RegExp(/^[1-9]\d*$/) - // ROUTES // GET ALL ------------------ const getUsers = () => { @@ -40,16 +38,16 @@ router.get('/', async (req, res) => { }) -// GET ONE ------------------ -const getUser = (id) => { - return Users.getOne(id) +// GET ONE FORM UUID ------------------ +const getUserFromUUID = (uuid) => { + return Users.getOneFromUUID(uuid) .catch(err => { console.log(err) throw err }) } -router.get('/:id/', async (req, res) => { - getUser(req.params.id) +router.get('/:uuid/', async (req, res) => { + getUserFromUUID(req.params.uuid) .then(v => { res.setHeader('Content-Type', 'application/json;charset=utf-8') res.end(JSON.stringify(v)) @@ -67,33 +65,9 @@ router.get('/:id/', async (req, res) => { // CREATE ONE ------------------ const addUser = (u) => { - return new Promise(async (resolve, reject) => { - - // Checks if body exists and if the model fits, and throws errors if it doesn't - if (isEmptyObject(u)) { - reject(new HttpError(403, "Error: User cannot be empty !")) - } else if (!v.validate(u, User).valid) { - reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(u, User).errors)) - } else if (isXSSAttempt(u.name) || isXSSAttempt(u.mail) || isXSSAttempt(u.password)) { - reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) - } else { - let query = `INSERT INTO user (name, mail, password) VALUES (${db.escape(u.name)}, ${db.escape(u.mail)}, ${db.escape(u.password)})` - - db.query(query, async (err, result) => { - if (err) { - reject(new HttpError(500, 'Database error')) - } else { - console.log(`Inserted "${u.name}" with ID ${result.insertId}, affecting ${result.affectedRows} row(s)`) - const new_user_id = result.insertId - let response = { - "message": `User created successfully !`, - "inserted_id": `${new_user_id}` - } - resolve(response) - } - }) - } - }).catch(err => { + return Users.addOne(u) + .catch(err => { + console.log(err) throw err }) } @@ -113,77 +87,4 @@ router.post('/', async (req, res) => { }) }) - -// DELETE ONE ------------------ -const deleteUser = (id) => { - return new Promise(async (resolve, reject) => { - - // Check if user exists - let old_user = await getUser(id) - .catch(() => { - reject((new HttpError(404, 'No user matching this ID'))) - }) - - console.log(old_user) - - let deleteUserData = () => { - return new Promise((resolve, reject) => { - let delete_user_query = `DELETE FROM user WHERE id = ${db.escape(id)}` - db.query(delete_user_query, async (err, result) => { - if (err) { - console.log(err) - reject(new HttpError(500, 'Spell deletion failed')) - } else { - let response = { - "message": "User delete successully", - "deleted_id": `${id}` - } - resolve(response) - } - }) - }) - } - - deleteUserData() - .then(v => { - resolve(v) - }) - .catch(err => { - reject(err) - }) - }) - .catch(err => { - throw err - }) -} -router.delete('/:id/', async (req, res) => { - deleteUser(req.params.id) - .then(v => { - res.setHeader('Content-Type', 'application/json;charset=utf-8') - res.send(JSON.stringify(v)) - }) - .catch(err => { - res.status(err.code).send(JSON.stringify( - { - "error": err.message, - "code": err.code - }) - ) - }) -}) - -// Param validation for single user -// (check if id is int) (could be refactored) -router.param('id', (req, res, next, id) => { - try { - if (regexInt.test(id)) { - next() - } else { - new Error - } - } catch (err) { - throw new HttpError(403, 'Provided ID must be an integer and not zero') - } -}) - module.exports = router \ No newline at end of file diff --git a/validations/UserValidation.js b/validations/UserValidation.js index 1dc9290..4ea8968 100644 --- a/validations/UserValidation.js +++ b/validations/UserValidation.js @@ -5,7 +5,6 @@ const User = { "name": { "type": "string" }, "mail": { "type": "string" }, "password": { "type": "string" }, - "banned": { "type": "boolean"}, }, "required": ["name", "password", "mail"] } From e6f0ee38aa3e448136da623a28e88d400314a73a Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Fri, 3 Jul 2020 21:44:01 +0200 Subject: [PATCH 18/31] - Added add user methods (will need polish imo) --- database/auracle_db_create.sql | 4 --- repositories/user-repository.js | 62 +++++++++++++++++++++++++-------- routes/users.js | 7 ++-- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/database/auracle_db_create.sql b/database/auracle_db_create.sql index 221d642..2f62e0c 100644 --- a/database/auracle_db_create.sql +++ b/database/auracle_db_create.sql @@ -128,10 +128,6 @@ INSERT INTO `role` (name, description) VALUES ("Arcanologue", "Maîtres de l'arcane, ils ont le pouvoir et la responsabilité de juger les sortilèges récents et de les supprimer, ou valider."), ("Augure", "Régents des grimoires, ils ont droit d'accès à l'intégralité des informations connues, et pouvoir absolu sur le savoir arcanique."); --- USERS -INSERT INTO `user` (uuid, name, mail, password, role_id) VALUES -("6af978f0-96ed-11e8-bb38-37f5ae311cf6", "Izàc Tymos", "tymos@ambrose.edu", "root", 4); - -- META SCHOOLS INSERT INTO `meta_school` (name, description) VALUES ('Magies blanches', 'Magies disciplinant les arts de soins et de lumières.'), diff --git a/repositories/user-repository.js b/repositories/user-repository.js index 3e44083..a93d034 100644 --- a/repositories/user-repository.js +++ b/repositories/user-repository.js @@ -33,13 +33,12 @@ class UserRepository { resolve(v.toJSON({ omitPivot: true })) }) .catch(err => { - console.log(err) reject(new HttpError(500, "Couldn't get users")) }) }) } - getOneFromUUID(uuid) { + getOneByUUID(uuid) { return new Promise((resolve, reject) => { model.forge() .where({ 'uuid' : uuid }) @@ -48,12 +47,37 @@ class UserRepository { resolve(v.toJSON({ omitPivot: true })) }) .catch(err => { - console.log(err) reject(new HttpError(500, "Couldn't get user")) }) }) } + getOneByEmail(mail) { + return new Promise((resolve, reject) => { + model.forge() + .where({ 'mail': mail}) + .fetch() + .then(v => { + resolve(v.toJSON({ omitPivot: true })) + }) + .catch(err => { + reject(new HttpError(500, "Couldn't get user")) + }) + }) + } + + checkIfEmailAvailable(mail) { + return new Promise((resolve, reject) => { + this.getOneByEmail(mail) + .then(() => { + reject(false) + }) + .catch(() => { + resolve(true) + }) + }) + } + addOne(u) { return new Promise(async (resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't @@ -67,22 +91,32 @@ class UserRepository { let hash = await bcrypt.hash(u.password, 10) let uuid = uuidv4() - // Needs to account for duplicate emails - bookshelf.transaction(t => { - return model.forge({ - 'uuid': uuid, - 'name': u.name, - 'mail': u.mail, - 'password': hash, + this.checkIfEmailAvailable(u.mail) + .then(() => { + bookshelf.transaction(t => { + return model.forge({ + 'uuid': uuid, + 'name': u.name, + 'mail': u.mail, + 'password': hash, + }) + .save(null, { + transacting: t + }) + .catch(err => { + console.log(err) + }) }) - .save(null, { - transacting: t + .then(v => { + resolve(this.getOneByUUID(uuid)) }) .catch(err => { - console.log(err) + throw err }) }) - + .catch(() => { + reject(new HttpError(403, 'Email is already in use !')) + }) } }) } diff --git a/routes/users.js b/routes/users.js index 427d801..c6af63d 100644 --- a/routes/users.js +++ b/routes/users.js @@ -39,15 +39,15 @@ router.get('/', async (req, res) => { // GET ONE FORM UUID ------------------ -const getUserFromUUID = (uuid) => { - return Users.getOneFromUUID(uuid) +const getUserByUUID = (uuid) => { + return Users.getOneByUUID(uuid) .catch(err => { console.log(err) throw err }) } router.get('/:uuid/', async (req, res) => { - getUserFromUUID(req.params.uuid) + getUserByUUID(req.params.uuid) .then(v => { res.setHeader('Content-Type', 'application/json;charset=utf-8') res.end(JSON.stringify(v)) @@ -67,7 +67,6 @@ router.get('/:uuid/', async (req, res) => { const addUser = (u) => { return Users.addOne(u) .catch(err => { - console.log(err) throw err }) } From 5d1b44cf6d6d54ee60160d60459c81ce57c09f8a Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Fri, 3 Jul 2020 22:19:31 +0200 Subject: [PATCH 19/31] - Added more pages and fixed some links (schools, single spell, and login page) --- .../src/components/global/navbar/navbar.vue | 13 ++++++--- client/src/components/spells/spell-card.vue | 4 +-- client/src/pages/index-page.vue | 2 +- client/src/pages/schools/schools-page.vue | 15 +++++++++++ .../src/pages/schools/single-school-page.vue | 12 ++++----- client/src/pages/spells-page.vue | 19 ------------- client/src/pages/spells/single-spell-page.vue | 15 +++++++++++ client/src/pages/spells/spells-page.vue | 19 +++++++++++++ client/src/pages/user/login-page.vue | 15 +++++++++++ client/src/routes.js | 27 ++++++++++++++----- 10 files changed, 104 insertions(+), 37 deletions(-) create mode 100644 client/src/pages/schools/schools-page.vue delete mode 100644 client/src/pages/spells-page.vue create mode 100644 client/src/pages/spells/single-spell-page.vue create mode 100644 client/src/pages/spells/spells-page.vue create mode 100644 client/src/pages/user/login-page.vue diff --git a/client/src/components/global/navbar/navbar.vue b/client/src/components/global/navbar/navbar.vue index ebd62ef..0ad8807 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -1,15 +1,18 @@ @@ -22,8 +25,12 @@ links: [ { text: 'Sortilèges', - url: '/spells', + url: '/sorts', }, + { + text: 'Écoles', + url: '/ecoles', + } ] } } diff --git a/client/src/components/spells/spell-card.vue b/client/src/components/spells/spell-card.vue index 27bbbae..2ae4a13 100644 --- a/client/src/components/spells/spell-card.vue +++ b/client/src/components/spells/spell-card.vue @@ -5,7 +5,7 @@
- {{spell.name}} + {{spell.name}}
@@ -14,7 +14,7 @@
, - {{school.name}} + {{school.name}}
diff --git a/client/src/pages/index-page.vue b/client/src/pages/index-page.vue index c2a1451..ee8a352 100644 --- a/client/src/pages/index-page.vue +++ b/client/src/pages/index-page.vue @@ -13,7 +13,7 @@ diff --git a/client/src/pages/schools/schools-page.vue b/client/src/pages/schools/schools-page.vue new file mode 100644 index 0000000..34fc10a --- /dev/null +++ b/client/src/pages/schools/schools-page.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/client/src/pages/schools/single-school-page.vue b/client/src/pages/schools/single-school-page.vue index 6681379..4dc4f8e 100644 --- a/client/src/pages/schools/single-school-page.vue +++ b/client/src/pages/schools/single-school-page.vue @@ -1,9 +1,9 @@ - - \ No newline at end of file diff --git a/client/src/pages/spells/single-spell-page.vue b/client/src/pages/spells/single-spell-page.vue new file mode 100644 index 0000000..dbaf519 --- /dev/null +++ b/client/src/pages/spells/single-spell-page.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/client/src/pages/spells/spells-page.vue b/client/src/pages/spells/spells-page.vue new file mode 100644 index 0000000..91388ae --- /dev/null +++ b/client/src/pages/spells/spells-page.vue @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/client/src/pages/user/login-page.vue b/client/src/pages/user/login-page.vue new file mode 100644 index 0000000..111a7ba --- /dev/null +++ b/client/src/pages/user/login-page.vue @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/client/src/routes.js b/client/src/routes.js index c74327c..d3480a5 100644 --- a/client/src/routes.js +++ b/client/src/routes.js @@ -1,7 +1,13 @@ // Pages -import Index from "./pages/index-page"; -import Spells from "./pages/spells-page"; -import SchoolSingle from "./pages/schools/single-school-page"; +import Index from "~/pages/index-page" + +import Spells from "~/pages/spells/spells-page" +import SpellSingle from "~/pages/spells/single-spell-page" + +import Schools from "./pages/schools/schools-page" +import SchoolSingle from "~/pages/schools/single-school-page" + +import Login from "~/pages/user/login-page" // Routes const routes = [ @@ -12,11 +18,20 @@ const routes = [ path: '/', component: Index, }, { - path: '/spells', component: Spells, + path: '/sorts', component: Spells, }, { - path: '/school/:id', component: SchoolSingle, props: true - } + path: '/sorts/:id', component: SpellSingle, props: true, + }, + { + path: '/ecoles', component: Schools, + }, + { + path: '/ecoles/:id', component: SchoolSingle, props: true, + }, + { + path: '/connexion', component: Login, + }, ]; export default routes; \ No newline at end of file From ba89dc8c5ef89979367e8806c997b03bd830e152 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sat, 4 Jul 2020 23:07:52 +0200 Subject: [PATCH 20/31] - Added login method for users --- repositories/user-repository.js | 74 +++++++++++++++++++++++++-------- routes/users.js | 24 +++++++++++ 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/repositories/user-repository.js b/repositories/user-repository.js index a93d034..e1a6d2e 100644 --- a/repositories/user-repository.js +++ b/repositories/user-repository.js @@ -52,13 +52,13 @@ class UserRepository { }) } - getOneByEmail(mail) { + getOneByEmail(mail, full) { return new Promise((resolve, reject) => { model.forge() - .where({ 'mail': mail}) + .where({ 'mail': mail }) .fetch() .then(v => { - resolve(v.toJSON({ omitPivot: true })) + resolve(v.toJSON({ omitPivot: true, visibility: !full })) }) .catch(err => { reject(new HttpError(500, "Couldn't get user")) @@ -66,18 +66,6 @@ class UserRepository { }) } - checkIfEmailAvailable(mail) { - return new Promise((resolve, reject) => { - this.getOneByEmail(mail) - .then(() => { - reject(false) - }) - .catch(() => { - resolve(true) - }) - }) - } - addOne(u) { return new Promise(async (resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't @@ -104,11 +92,21 @@ class UserRepository { transacting: t }) .catch(err => { - console.log(err) + throw err }) }) - .then(v => { - resolve(this.getOneByUUID(uuid)) + .then(() => { + return this.getOneByUUID(uuid) + }) + .then(newUser => { + resolve({ + "message": "Account successfully created !", + "data": { + "uuid": newUser.uuid, + "name": newUser.name, + "mail": newUser.mail, + }, + }) }) .catch(err => { throw err @@ -120,6 +118,46 @@ class UserRepository { } }) } + + // Log user with an email address and a password + logUser(mail, password) { + return new Promise((resolve, reject) => { + this.getOneByEmail(mail, true) + .then(async fetchedUser => { + let match = await bcrypt.compare(password, fetchedUser.password) + if (match) { + resolve({ + "message": "User successfully logged in !", + "logged?": true, + "data": { + "uuid": fetchedUser.uuid + }, + }) + } else { + resolve({ + "message": "The email and passwords don't match", + "logged?": false, + }) + } + }) + .catch(err => { + reject(err) + }) + }) + } + + // Check if one user already has that email + checkIfEmailAvailable(mail) { + return new Promise((resolve, reject) => { + this.getOneByEmail(mail, false) + .then(() => { + reject(false) + }) + .catch(() => { + resolve(true) + }) + }) + } } module.exports = UserRepository \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index c6af63d..6219953 100644 --- a/routes/users.js +++ b/routes/users.js @@ -63,6 +63,30 @@ router.get('/:uuid/', async (req, res) => { }) +// LOG A USER ------------------ +const logUser = (mail, password) => { + return Users.logUser(mail, password) + .catch(err => { + console.log(err) + throw err + }) +} +router.post('/login', async (req, res) => { + logUser(req.body.mail, req.body.password) + .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 + }) + ) + }) +}) + // CREATE ONE ------------------ const addUser = (u) => { return Users.addOne(u) From 4779e9d25ec64fd560811641ee2738490f1336e8 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 5 Jul 2020 21:19:46 +0200 Subject: [PATCH 21/31] - Reworked some error handling and polished messages for users --- repositories/user-repository.js | 77 ++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/repositories/user-repository.js b/repositories/user-repository.js index e1a6d2e..6bd5174 100644 --- a/repositories/user-repository.js +++ b/repositories/user-repository.js @@ -17,9 +17,6 @@ v.addSchema(UserValidation, "/UserValidation") const isXSSAttempt = require('../functions').isXSSAttempt const isEmptyObject = require('../functions').isEmptyObject -// Error handling -const { HttpError } = require('../validations/Errors') - class UserRepository { constructor() { @@ -32,22 +29,28 @@ class UserRepository { .then(v => { resolve(v.toJSON({ omitPivot: true })) }) - .catch(err => { - reject(new HttpError(500, "Couldn't get users")) + .catch(() => { + reject({ + "message": "Database error, couldn't get all users.", + "code": 500 + }) }) }) } - getOneByUUID(uuid) { + getOneByUUID(uuid, full) { return new Promise((resolve, reject) => { model.forge() .where({ 'uuid' : uuid }) .fetch() .then(v => { - resolve(v.toJSON({ omitPivot: true })) + resolve(v.toJSON({ omitPivot: true, visibility: !full })) }) .catch(err => { - reject(new HttpError(500, "Couldn't get user")) + reject({ + "message": "User with this UUID was not found.", + "code": 404 + }) }) }) } @@ -60,8 +63,11 @@ class UserRepository { .then(v => { resolve(v.toJSON({ omitPivot: true, visibility: !full })) }) - .catch(err => { - reject(new HttpError(500, "Couldn't get user")) + .catch(() => { + reject({ + "message": "User with this email was not found.", + "code": 404 + }) }) }) } @@ -70,11 +76,20 @@ class UserRepository { return new Promise(async (resolve, reject) => { // Checks if body exists and if the model fits, and throws errors if it doesn't if (isEmptyObject(u)) { - reject(new HttpError(403, "Error: User cannot be nothing !")) + reject({ + "message": "Request body cannot be empty.", + "code": 403 + }) } else if (!v.validate(u, UserValidation).valid) { - reject(new HttpError(403, "Error: Schema is not valid - " + v.validate(u, UserValidation).errors)) + reject({ + "message": "Schema is not valid - " + v.validate(u, UserValidation).errors, + "code": 403 + }) } else if (isXSSAttempt(u.name) || isXSSAttempt(u.password) || isXSSAttempt(u.mail)) { - reject(new HttpError(403, 'Injection attempt detected, aborting the request.')) + reject({ + "message": "Injection attempt detected, aborting the request.", + "code": 403 + }) } else { let hash = await bcrypt.hash(u.password, 10) let uuid = uuidv4() @@ -96,24 +111,23 @@ class UserRepository { }) }) .then(() => { - return this.getOneByUUID(uuid) + return this.getOneByUUID(uuid, false) }) .then(newUser => { resolve({ "message": "Account successfully created !", - "data": { - "uuid": newUser.uuid, - "name": newUser.name, - "mail": newUser.mail, - }, + "user": newUser, }) }) .catch(err => { - throw err + resolve({ + "message": "An error has occured while creating your account.", + "code": 500, + }) }) }) - .catch(() => { - reject(new HttpError(403, 'Email is already in use !')) + .catch(err => { + reject(err) }) } }) @@ -124,19 +138,19 @@ class UserRepository { return new Promise((resolve, reject) => { this.getOneByEmail(mail, true) .then(async fetchedUser => { + let match = await bcrypt.compare(password, fetchedUser.password) + delete fetchedUser.id + delete fetchedUser.password + if (match) { resolve({ "message": "User successfully logged in !", - "logged?": true, - "data": { - "uuid": fetchedUser.uuid - }, + "user": fetchedUser, }) } else { - resolve({ - "message": "The email and passwords don't match", - "logged?": false, + reject({ + "message": "The email and passwords don't match.", }) } }) @@ -151,7 +165,10 @@ class UserRepository { return new Promise((resolve, reject) => { this.getOneByEmail(mail, false) .then(() => { - reject(false) + reject({ + "message": "Email is already in use !", + "code": 403 + }) }) .catch(() => { resolve(true) From 0a4a59f6e66474161d2bfd0cac18cca64dabe722 Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Sun, 5 Jul 2020 21:48:49 +0200 Subject: [PATCH 22/31] - Added pages for register and scoped styles --- client/src/assets/scss/_global.scss | 8 ++++ .../src/components/global/navbar/navbar.vue | 3 +- client/src/pages/index-page.vue | 45 ++++++++----------- client/src/pages/user/login-page.vue | 24 +++++++--- client/src/pages/user/register-page.vue | 25 +++++++++++ client/src/routes.js | 4 ++ 6 files changed, 75 insertions(+), 34 deletions(-) create mode 100644 client/src/pages/user/register-page.vue diff --git a/client/src/assets/scss/_global.scss b/client/src/assets/scss/_global.scss index 6c57871..dea2e02 100644 --- a/client/src/assets/scss/_global.scss +++ b/client/src/assets/scss/_global.scss @@ -49,4 +49,12 @@ hr { border-top-style: solid; border-top-width: 1px; border-top-color: rgba($black, .25); +} + +// LAYOUTS +.fullpage { + min-height: calc(100vh - 56px); + display: flex; + justify-content: center; + align-items: center; } \ 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 0ad8807..db97f88 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -11,7 +11,8 @@
diff --git a/client/src/pages/index-page.vue b/client/src/pages/index-page.vue index ee8a352..0100af5 100644 --- a/client/src/pages/index-page.vue +++ b/client/src/pages/index-page.vue @@ -1,14 +1,14 @@ - \ No newline at end of file diff --git a/client/src/pages/user/login-page.vue b/client/src/pages/user/login-page.vue index 111a7ba..2f4bb2f 100644 --- a/client/src/pages/user/login-page.vue +++ b/client/src/pages/user/login-page.vue @@ -1,15 +1,25 @@ - \ No newline at end of file diff --git a/client/src/pages/user/register-page.vue b/client/src/pages/user/register-page.vue new file mode 100644 index 0000000..d254b84 --- /dev/null +++ b/client/src/pages/user/register-page.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/client/src/routes.js b/client/src/routes.js index d3480a5..b442e0a 100644 --- a/client/src/routes.js +++ b/client/src/routes.js @@ -8,6 +8,7 @@ import Schools from "./pages/schools/schools-page" import SchoolSingle from "~/pages/schools/single-school-page" import Login from "~/pages/user/login-page" +import Register from "~/pages/user/register-page" // Routes const routes = [ @@ -32,6 +33,9 @@ const routes = [ { path: '/connexion', component: Login, }, + { + path: '/inscription', component: Register, + }, ]; export default routes; \ No newline at end of file From 78587f8544cd6ae6498963b0943deb58baec20ee Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 6 Jul 2020 12:49:09 +0200 Subject: [PATCH 23/31] - Added basic user login --- client/package-lock.json | 5 ++ client/package.json | 1 + client/src/api/repositories.js | 2 + client/src/api/usersRepository.js | 12 ++++ .../src/components/global/navbar/navbar.vue | 1 + client/src/main.js | 20 +++--- client/src/pages/user/login-page.vue | 53 ++++++++++++++- client/src/pages/user/profile-page.vue | 25 ++++++++ client/src/routes.js | 64 ++++++++++++++++--- 9 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 client/src/api/usersRepository.js create mode 100644 client/src/pages/user/profile-page.vue diff --git a/client/package-lock.json b/client/package-lock.json index e53b9cb..8aa7da7 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11960,6 +11960,11 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" }, + "vue-cookies": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.7.0.tgz", + "integrity": "sha512-vuEUm6wYMMrFAHFCrkzIUAy8+MgPAbBGmYXnk2M6X6O2KHbMT1wuDD2izacmsSUp6ZM02e23MJRtPRobl88VMg==" + }, "vue-eslint-parser": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.0.0.tgz", diff --git a/client/package.json b/client/package.json index dea18a1..1cd78c3 100644 --- a/client/package.json +++ b/client/package.json @@ -35,6 +35,7 @@ "popper.js": "^1.16.1", "v-clipboard": "^2.2.3", "vue": "^2.6.11", + "vue-cookies": "^1.7.0", "vue-masonry": "^0.11.8" }, "devDependencies": { diff --git a/client/src/api/repositories.js b/client/src/api/repositories.js index a663bfa..96fddd7 100644 --- a/client/src/api/repositories.js +++ b/client/src/api/repositories.js @@ -3,6 +3,7 @@ import schoolsRepository from './schoolsRepository' import metaschoolsRepository from './metaschoolsRepository' import variablesRepository from './variablesRepository' import ingredientsRepository from './ingredientsRepository' +import usersRepository from './usersRepository' // List of possible repositories const repositories = { @@ -11,6 +12,7 @@ const repositories = { metaschools: metaschoolsRepository, variables: variablesRepository, ingredients: ingredientsRepository, + users: usersRepository, } // Usage : RepositoryFactoryInstance.get('reponame'); diff --git a/client/src/api/usersRepository.js b/client/src/api/usersRepository.js new file mode 100644 index 0000000..9320855 --- /dev/null +++ b/client/src/api/usersRepository.js @@ -0,0 +1,12 @@ +import api from './api' + +const resource = "/users" + +export default { + login(data) { + return api.post(`${resource}/login`, data) + }, + addOne(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 db97f88..20b899c 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -11,6 +11,7 @@ diff --git a/client/src/main.js b/client/src/main.js index 9f46591..d4de66a 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -8,9 +8,13 @@ Globals.forEach(component => { Vue.component(component.name, component) }); -// Auth +// Environment require('dotenv').config() +// Cookies +import VueCookies from 'vue-cookies' +Vue.use(VueCookies) + // Jquery import jquery from 'jquery' window.$ = jquery @@ -26,7 +30,7 @@ import 'bootstrap/dist/js/bootstrap.js' import { BootstrapVue } from 'bootstrap-vue' Vue.use(BootstrapVue) -import { VueMasonryPlugin } from 'vue-masonry'; +import { VueMasonryPlugin } from 'vue-masonry' Vue.use(VueMasonryPlugin) import clipboard from 'v-clipboard' @@ -39,18 +43,12 @@ var filter = function(text, length, clamp){ node.innerHTML = text; var content = node.textContent; return content.length > length ? content.slice(0, length) + clamp : content; -}; -Vue.filter('truncate', filter); +} +Vue.filter('truncate', filter) // Router -import routes from './routes' +import router from './routes' Vue.use(VueRouter) -const router = new VueRouter({ - mode: 'history', - routes, - linkActiveClass: "", - linkExactActiveClass: "active", -}); // Mount Vue const app = new Vue({ diff --git a/client/src/pages/user/login-page.vue b/client/src/pages/user/login-page.vue index 2f4bb2f..e2db8f0 100644 --- a/client/src/pages/user/login-page.vue +++ b/client/src/pages/user/login-page.vue @@ -1,14 +1,65 @@ diff --git a/client/src/pages/user/profile-page.vue b/client/src/pages/user/profile-page.vue new file mode 100644 index 0000000..944eb37 --- /dev/null +++ b/client/src/pages/user/profile-page.vue @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/client/src/routes.js b/client/src/routes.js index b442e0a..8ca8eaa 100644 --- a/client/src/routes.js +++ b/client/src/routes.js @@ -1,3 +1,6 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' + // Pages import Index from "~/pages/index-page" @@ -9,33 +12,74 @@ import SchoolSingle from "~/pages/schools/single-school-page" import Login from "~/pages/user/login-page" import Register from "~/pages/user/register-page" +import Profile from "~/pages/user/profile-page" // Routes const routes = [ { - path: "*", redirect: "/", + path: "*", + redirect: "/", }, { - path: '/', component: Index, + path: '/', + component: Index, }, { - path: '/sorts', component: Spells, + path: '/connexion', + component: Login, }, { - path: '/sorts/:id', component: SpellSingle, props: true, + path: '/inscription', + component: Register, }, { - path: '/ecoles', component: Schools, + path: '/sorts', + component: Spells, }, { - path: '/ecoles/:id', component: SchoolSingle, props: true, + path: '/sorts/:id', + component: SpellSingle, + props: true, }, { - path: '/connexion', component: Login, + path: '/ecoles', + component: Schools, }, { - path: '/inscription', component: Register, + path: '/ecoles/:id', + component: SchoolSingle, + props: true, }, -]; + { + path: '/profil', + component: Profile, + props: true, + meta: { + authGuard: true, + } + }, +] -export default routes; \ No newline at end of file +const router = new VueRouter({ + mode: 'history', + routes, + linkActiveClass: "", + linkExactActiveClass: "active", +}) + +router.beforeEach((to, from, next) => { + if (to.matched.some(record => record.meta.authGuard)) { + if (Vue.$cookies.get('loggedUser') == null) { + next({ + path: '/connexion', + params: { nextUrl: to.fullPath } + }) + } else { + next() + } + } else { + next() + } +}) + +export default router; \ No newline at end of file From 27ab62e36fcbe901d3ef30c864190f65c8c4461b Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 6 Jul 2020 18:24:54 +0200 Subject: [PATCH 24/31] - Added login check for navbar actions --- client/src/components/global/navbar/navbar.vue | 8 ++++++-- client/src/main.js | 1 + client/src/pages/user/login-page.vue | 3 +-- client/src/pages/user/profile-page.vue | 11 +++++++---- client/src/routes.js | 4 ++-- package.json | 3 ++- 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/client/src/components/global/navbar/navbar.vue b/client/src/components/global/navbar/navbar.vue index 20b899c..99f0d9a 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -10,10 +10,13 @@ {{ link.text }} - @@ -24,6 +27,7 @@ name: 'navbar', data() { return { + user: this.$cookies.get("U_"), links: [ { text: 'Sortilèges', diff --git a/client/src/main.js b/client/src/main.js index d4de66a..c5f47a7 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -14,6 +14,7 @@ require('dotenv').config() // Cookies import VueCookies from 'vue-cookies' Vue.use(VueCookies) +Vue.$cookies.config('30d','','') // Jquery import jquery from 'jquery' diff --git a/client/src/pages/user/login-page.vue b/client/src/pages/user/login-page.vue index e2db8f0..b201808 100644 --- a/client/src/pages/user/login-page.vue +++ b/client/src/pages/user/login-page.vue @@ -52,8 +52,7 @@ export default { "password": this.password }) .then(v => { - let user = v.data - this.$cookies.set("loggedUser", user, 60 * 60 * 24 * 30) + this.$cookies.set("U_", v.data.user, 60 * 60 * 24 * 30) }) .catch(err => { console.log(err) diff --git a/client/src/pages/user/profile-page.vue b/client/src/pages/user/profile-page.vue index 944eb37..b24c702 100644 --- a/client/src/pages/user/profile-page.vue +++ b/client/src/pages/user/profile-page.vue @@ -1,14 +1,17 @@ diff --git a/client/src/routes.js b/client/src/routes.js index 8ca8eaa..e19646a 100644 --- a/client/src/routes.js +++ b/client/src/routes.js @@ -69,10 +69,10 @@ const router = new VueRouter({ router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.authGuard)) { - if (Vue.$cookies.get('loggedUser') == null) { + if (Vue.$cookies.get('U_') == null) { next({ path: '/connexion', - params: { nextUrl: to.fullPath } + params: { nextUrl: to.fullPath }, }) } else { next() diff --git a/package.json b/package.json index 0e4bf54..f93fffe 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "API for Auracle database", "main": "index.js", "scripts": { - "test": "start" + "api": "node index.js", + "client": "cd client && npm run serve" }, "repository": { "type": "git", From 9b10cd473e4ddb68ac69ac92529eb104cdb44bae Mon Sep 17 00:00:00 2001 From: Alexis <35.alexis.pele@gmail.com> Date: Mon, 6 Jul 2020 21:22:03 +0200 Subject: [PATCH 25/31] - Implemented store and logged states --- client/package-lock.json | 5 +++ client/package.json | 3 +- client/src/assets/scss/_global.scss | 5 +++ .../src/components/global/navbar/navbar.vue | 19 ++++++++-- client/src/main.js | 36 ++++++++++++++++++- client/src/pages/user/login-page.vue | 6 +++- 6 files changed, 68 insertions(+), 6 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 8aa7da7..0103e23 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12073,6 +12073,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vuex": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.5.1.tgz", + "integrity": "sha512-w7oJzmHQs0FM9LXodfskhw9wgKBiaB+totOdb8sNzbTB2KDCEEwEs29NzBZFh/lmEK1t5tDmM1vtsO7ubG1DFw==" + }, "watchpack": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", diff --git a/client/package.json b/client/package.json index 1cd78c3..b68acd3 100644 --- a/client/package.json +++ b/client/package.json @@ -36,7 +36,8 @@ "v-clipboard": "^2.2.3", "vue": "^2.6.11", "vue-cookies": "^1.7.0", - "vue-masonry": "^0.11.8" + "vue-masonry": "^0.11.8", + "vuex": "^3.5.1" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.2.0", diff --git a/client/src/assets/scss/_global.scss b/client/src/assets/scss/_global.scss index dea2e02..8968aae 100644 --- a/client/src/assets/scss/_global.scss +++ b/client/src/assets/scss/_global.scss @@ -51,6 +51,11 @@ hr { border-top-color: rgba($black, .25); } +// BOOTSTRAP +.nav-link { + cursor: pointer; +} + // LAYOUTS .fullpage { min-height: calc(100vh - 56px); diff --git a/client/src/components/global/navbar/navbar.vue b/client/src/components/global/navbar/navbar.vue index 99f0d9a..8a8a473 100644 --- a/client/src/components/global/navbar/navbar.vue +++ b/client/src/components/global/navbar/navbar.vue @@ -10,9 +10,9 @@ {{ link.text }} -