Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da6cd44987 | ||
|
|
4b25f63531 | ||
|
|
b318a88023 | ||
|
|
615cced6ed | ||
|
|
b5e6f73d01 | ||
|
|
efb9195053 | ||
|
|
e2061d6595 | ||
|
|
e8ca2416b7 | ||
|
|
410a58fc09 | ||
|
|
413d458a80 | ||
|
|
bb721e6ab4 | ||
|
|
39ee29c65a | ||
|
|
b7cc851cd6 | ||
|
|
d3c5e0a20c | ||
|
|
7170eb0dee | ||
|
|
50ba8b7f9c | ||
|
|
e9640ec2d2 | ||
|
|
2b3b890228 | ||
|
|
16b7b81166 | ||
|
|
5cf2c1daa7 | ||
|
|
2959d777b7 | ||
|
|
b313393af6 | ||
|
|
1759f71876 | ||
|
|
dde2e63b61 | ||
|
|
41575f40db | ||
|
|
70283da8e0 | ||
|
|
0a77206bcb | ||
|
|
28c869070a | ||
|
|
3bdf43d11b | ||
|
|
0fd0253fb4 | ||
|
|
23ab785163 | ||
|
|
f7a09c02ae | ||
|
|
5f7e5499f7 | ||
|
|
3c2326ef92 | ||
|
|
752cfb4227 | ||
|
|
1b11db4890 | ||
|
|
32c17407e2 | ||
|
|
da73fa5241 | ||
|
|
d64e447b67 | ||
|
|
dba451c588 | ||
|
|
39521f063a | ||
|
|
1ea21df4d9 | ||
|
|
10fdbade66 | ||
|
|
bdfdb1d21e | ||
|
|
dba0521ad9 | ||
|
|
c9bd0aa0ab | ||
|
|
15ba9e19c9 | ||
|
|
d311042b51 | ||
|
|
3cf131ef6f | ||
|
|
1ac0968e57 | ||
|
|
36a82a643e | ||
|
|
79c34a6ad1 | ||
|
|
167722fab6 | ||
|
|
a95a617e8b | ||
|
|
b8e12c1665 | ||
|
|
7b932f1b86 | ||
|
|
d69ea0fa72 | ||
|
|
02c0216c26 | ||
|
|
ad84673fba | ||
|
|
1e334b8c05 | ||
|
|
01df57f510 | ||
|
|
772b225072 | ||
|
|
65abb41a9f | ||
|
|
fdad47e84e | ||
|
|
20f946a945 | ||
|
|
597307be40 | ||
|
|
eba2669176 | ||
|
|
fa945e45c9 | ||
|
|
0587656ba6 | ||
|
|
de90b7d747 | ||
|
|
0178f15bf1 | ||
|
|
b89839c8fd | ||
|
|
a2d5d89487 | ||
|
|
7dbaabd7a5 | ||
|
|
d7631cb0e8 | ||
|
|
867fa50dfe | ||
|
|
9467926745 | ||
|
|
ab9ff12d09 | ||
|
|
bf03470a17 | ||
|
|
ddcc6acc75 | ||
|
|
71423a2172 | ||
|
|
cbeaad410f | ||
|
|
78a7219883 | ||
|
|
0855252b7e | ||
|
|
62535a9c91 | ||
|
|
256867a291 | ||
|
|
8ab53a4529 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
@@ -21,4 +21,8 @@ yarn-error.log*
|
||||
*.sw?
|
||||
|
||||
# creds
|
||||
.env
|
||||
.env
|
||||
|
||||
# db files
|
||||
*.csv
|
||||
*.ods
|
||||
230
api/database/auracle_db_create.sql
Normal file
230
api/database/auracle_db_create.sql
Normal file
@@ -0,0 +1,230 @@
|
||||
DROP DATABASE IF EXISTS auracle;
|
||||
CREATE DATABASE auracle CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
USE auracle;
|
||||
|
||||
/* =========== PRIMARY TABLES =========== */
|
||||
|
||||
-- ROLES
|
||||
CREATE TABLE IF NOT EXISTS `role` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
|
||||
-- PERMISSIONS
|
||||
CREATE TABLE IF NOT EXISTS `permission` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`slug` VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
|
||||
-- USERS
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`uuid` VARCHAR(36) NOT NULL UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Disciple",
|
||||
`mail` VARCHAR(255) NOT NULL,
|
||||
`avatar` VARCHAR(255),
|
||||
`gender` VARCHAR(255),
|
||||
`register_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`password` VARCHAR(255) NOT NULL,
|
||||
`role_id` INT UNSIGNED NOT NULL DEFAULT 1,
|
||||
`verified` BOOLEAN DEFAULT false,
|
||||
`verification_token` VARCHAR(255),
|
||||
`banned` BOOLEAN DEFAULT false,
|
||||
PRIMARY KEY(`id`),
|
||||
FOREIGN KEY(`role_id`) REFERENCES role(`id`)
|
||||
);
|
||||
|
||||
-- API_TOKENS
|
||||
CREATE TABLE IF NOT EXISTS `api_token` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`value` VARCHAR(255) NOT NULL,
|
||||
`user_uuid` VARCHAR(36) NOT NULL UNIQUE,
|
||||
PRIMARY KEY(`id`),
|
||||
FOREIGN KEY(`user_uuid`) REFERENCES user(`uuid`)
|
||||
);
|
||||
|
||||
-- SPELLS
|
||||
CREATE TABLE IF NOT EXISTS `spell` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`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,
|
||||
`published` BOOLEAN DEFAULT false,
|
||||
`public` BOOLEAN DEFAULT true,
|
||||
`author_id` INT UNSIGNED NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`),
|
||||
FOREIGN KEY(`author_id`) REFERENCES user(`id`)
|
||||
);
|
||||
|
||||
-- META SCHOOLS
|
||||
CREATE TABLE IF NOT EXISTS `meta_school` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Nom de l'école mère",
|
||||
`description` VARCHAR(255) DEFAULT "Description de l'école mère",
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
-- SCHOOLS
|
||||
CREATE TABLE IF NOT EXISTS `school` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Nom de l'école",
|
||||
`description` VARCHAR(255) DEFAULT "Description de l'école",
|
||||
`published` BOOLEAN DEFAULT false,
|
||||
`meta_school_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
FOREIGN KEY(`meta_school_id`) REFERENCES meta_school(`id`)
|
||||
);
|
||||
|
||||
-- COMMON INGREDIENTS
|
||||
CREATE TABLE IF NOT EXISTS `ingredient` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Langue de salamandre",
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT "Une langue de salamandre de feu encore chaude.",
|
||||
`published` BOOLEAN DEFAULT false,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
-- COMMON VARIABLES
|
||||
CREATE TABLE IF NOT EXISTS `variable` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT "Nombre de créatures affectées",
|
||||
`published` BOOLEAN DEFAULT false,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
/* ==== ASSOCIATION TABLES ==== */
|
||||
|
||||
-- SPELLS' SCHOOLS
|
||||
-- One spell can have multiple (up to 3) schools
|
||||
CREATE TABLE IF NOT EXISTS `spell_school` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`school_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `school_id`),
|
||||
FOREIGN KEY(`spell_id`) REFERENCES spell(`id`),
|
||||
FOREIGN KEY(`school_id`) REFERENCES school(`id`)
|
||||
);
|
||||
|
||||
-- SPELLS' VARIABLES
|
||||
-- One spell can have multiple (up to 2) variables of cost
|
||||
CREATE TABLE IF NOT EXISTS `spell_variable` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`variable_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `variable_id`),
|
||||
FOREIGN KEY(`spell_id`) REFERENCES spell(`id`),
|
||||
FOREIGN KEY(`variable_id`) REFERENCES variable(`id`)
|
||||
);
|
||||
|
||||
-- SPELLS' VARIABLES
|
||||
-- One spell can have multiple ingredients
|
||||
CREATE TABLE IF NOT EXISTS `spell_ingredient` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`ingredient_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `ingredient_id`),
|
||||
FOREIGN KEY(`spell_id`) REFERENCES spell(`id`),
|
||||
FOREIGN KEY(`ingredient_id`) REFERENCES ingredient(`id`)
|
||||
);
|
||||
|
||||
-- ROLES' PERMISSIONS
|
||||
-- One role can have any number of permissions, or none at all
|
||||
CREATE TABLE IF NOT EXISTS `role_permission` (
|
||||
`role_id` INT UNSIGNED NOT NULL,
|
||||
`permission_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`role_id`, `permission_id`),
|
||||
FOREIGN KEY(`role_id`) REFERENCES role(`id`),
|
||||
FOREIGN KEY(`permission_id`) REFERENCES permission(`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, "<l>", "\n");
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
/* =========== PRIMARY INSERTS =========== */
|
||||
SET NAMES utf8;
|
||||
|
||||
-- CSV DATA
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/permission.csv'
|
||||
INTO TABLE `permission`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/role.csv'
|
||||
INTO TABLE `role`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/role_permission.csv'
|
||||
INTO TABLE `role_permission`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/user.csv'
|
||||
INTO TABLE `user`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/api_token.csv'
|
||||
INTO TABLE `api_token`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/spell.csv'
|
||||
INTO TABLE `spell`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/meta_school.csv'
|
||||
INTO TABLE `meta_school`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/school.csv'
|
||||
INTO TABLE `school`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/ingredient.csv'
|
||||
INTO TABLE `ingredient`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/variable.csv'
|
||||
INTO TABLE `variable`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
|
||||
LOAD DATA INFILE 'C:/temp/auracle_data/spell_school.csv'
|
||||
INTO TABLE `spell_school`
|
||||
FIELDS TERMINATED BY ','
|
||||
ENCLOSED BY '"'
|
||||
LINES TERMINATED BY '\n'
|
||||
IGNORE 1 ROWS;
|
||||
14
api/database/bookshelf.js
Normal file
14
api/database/bookshelf.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// Setting up the database connection
|
||||
const knex = require('knex')({
|
||||
client: "mysql",
|
||||
connection: {
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE,
|
||||
charset: "utf8"
|
||||
},
|
||||
});
|
||||
const bookshelf = require('bookshelf')(knex);
|
||||
|
||||
module.exports = { bookshelf };
|
||||
35
api/functions.js
Normal file
35
api/functions.js
Normal file
@@ -0,0 +1,35 @@
|
||||
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) {
|
||||
res.status(err.code).send(JSON.stringify({
|
||||
"message": "Le paramètre doit être un entier non-nul.",
|
||||
"code": 403,
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if script injection attempt
|
||||
const isXSSAttempt = (string) => {
|
||||
return regexXSS.test(string);
|
||||
};
|
||||
|
||||
// Check if object is null
|
||||
const isEmptyObject = (obj) => {
|
||||
return (Object.keys(obj).length === 0 && obj.constructor === Object);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
paramIntCheck,
|
||||
isXSSAttempt,
|
||||
isEmptyObject
|
||||
};
|
||||
41
api/index.js
Normal file
41
api/index.js
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
// MODULES
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const helmet = require('helmet');
|
||||
const morgan = require('morgan');
|
||||
const cors = require('cors'); // module to format the json response
|
||||
require('dotenv').config();
|
||||
|
||||
// CONSTANTS
|
||||
const port = 2814;
|
||||
|
||||
// Import routes
|
||||
const routes = require('./routes');
|
||||
|
||||
// Builds app w/ express
|
||||
let app = express();
|
||||
app.use(bodyParser.json({ limit: '10kb' }));
|
||||
app.use(cors({
|
||||
origin: [
|
||||
"http://localhost:8080",
|
||||
],
|
||||
credentials: true,
|
||||
}));
|
||||
app.use(morgan('dev'));
|
||||
app.use(helmet());
|
||||
|
||||
// Server
|
||||
app.listen(port, () => console.log(`App listening on port ${port}`));
|
||||
|
||||
// Entry route
|
||||
app.use('/api/v1/', routes.auth);
|
||||
|
||||
// Routing
|
||||
app.use('/api/v1/spells', routes.spells);
|
||||
app.use('/api/v1/schools', routes.schools);
|
||||
app.use('/api/v1/meta_schools', routes.meta_schools);
|
||||
app.use('/api/v1/variables', routes.variables);
|
||||
app.use('/api/v1/ingredients', routes.ingredients);
|
||||
app.use('/api/v1/users', routes.users);
|
||||
13
api/models/api-token-model.js
Normal file
13
api/models/api-token-model.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./user-model');
|
||||
|
||||
let APIToken = bookshelf.Model.extend({
|
||||
tableName: 'api_token',
|
||||
hidden: ['id'],
|
||||
user() {
|
||||
return this.belongsTo('User', 'user_uuid', 'uuid');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('APIToken', APIToken);
|
||||
12
api/models/ingredient-model.js
Normal file
12
api/models/ingredient-model.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./spell-model');
|
||||
|
||||
let Ingredient = bookshelf.Model.extend({
|
||||
tableName: 'ingredient',
|
||||
spells() {
|
||||
return this.belongsToMany('Spell', 'spell_ingredient');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('Ingredient', Ingredient);
|
||||
12
api/models/meta-school-model.js
Normal file
12
api/models/meta-school-model.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./school-model');
|
||||
|
||||
let MetaSchool = bookshelf.Model.extend({
|
||||
tableName: 'meta_school',
|
||||
schools() {
|
||||
return this.hasMany('School');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('MetaSchool', MetaSchool);
|
||||
13
api/models/permission-model.js
Normal file
13
api/models/permission-model.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./role-model');
|
||||
|
||||
let Permission = bookshelf.Model.extend({
|
||||
tableName: 'permission',
|
||||
hidden: ['id'],
|
||||
role() {
|
||||
return this.belongsToMany('Role', 'role_permission');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('Permission', Permission);
|
||||
12
api/models/role-model.js
Normal file
12
api/models/role-model.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./permission-model');
|
||||
|
||||
let Role = bookshelf.Model.extend({
|
||||
tableName: 'role',
|
||||
permissions() {
|
||||
return this.belongsToMany('Permission', 'role_permission');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('Role', Role);
|
||||
16
api/models/school-model.js
Normal file
16
api/models/school-model.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./spell-model');
|
||||
require('./meta-school-model');
|
||||
|
||||
let School = bookshelf.Model.extend({
|
||||
tableName: 'school',
|
||||
spells() {
|
||||
return this.belongsToMany('Spell', 'spell_school');
|
||||
},
|
||||
meta_schools() {
|
||||
return this.belongsTo('MetaSchool', 'meta_school_id');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('School', School);
|
||||
24
api/models/spell-model.js
Normal file
24
api/models/spell-model.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./school-model');
|
||||
require('./variable-model');
|
||||
require('./ingredient-model');
|
||||
|
||||
let Spell = bookshelf.Model.extend({
|
||||
tableName: 'spell',
|
||||
hidden: [ 'author_id' ],
|
||||
author() {
|
||||
return this.belongsTo( 'User', 'author_id' );
|
||||
},
|
||||
schools() {
|
||||
return this.belongsToMany( 'School', 'spell_school' );
|
||||
},
|
||||
variables() {
|
||||
return this.belongsToMany( 'Variable', 'spell_variable' );
|
||||
},
|
||||
ingredients() {
|
||||
return this.belongsToMany( 'Ingredient', 'spell_ingredient' );
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('Spell', Spell);
|
||||
17
api/models/user-model.js
Normal file
17
api/models/user-model.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./role-model');
|
||||
require('./spell-model');
|
||||
|
||||
let User = bookshelf.Model.extend({
|
||||
tableName: 'user',
|
||||
hidden: ['password', 'role_id'],
|
||||
role() {
|
||||
return this.belongsTo('Role');
|
||||
},
|
||||
spells() {
|
||||
return this.hasMany('Spell', 'author_id');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('User', User);
|
||||
12
api/models/variable-model.js
Normal file
12
api/models/variable-model.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
|
||||
require('./spell-model');
|
||||
|
||||
let Variable = bookshelf.Model.extend({
|
||||
tableName: 'variable',
|
||||
spells() {
|
||||
return this.belongsToMany('Spell', 'spell_variable');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = bookshelf.model('Variable', Variable);
|
||||
3907
api/package-lock.json
generated
Normal file
3907
api/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
73
api/package.json
Normal file
73
api/package.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "auracle-api",
|
||||
"version": "1.0.0",
|
||||
"description": "API for Auracle database",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/AlexisNP/spellsaurus.git"
|
||||
},
|
||||
"keywords": [
|
||||
"api",
|
||||
"rpg",
|
||||
"spells",
|
||||
"magic",
|
||||
"database",
|
||||
"ttrpg",
|
||||
"dices",
|
||||
"worldbuilding"
|
||||
],
|
||||
"author": "AlexisNP",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/AlexisNP/spellsaurus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/AlexisNP/spellsaurus#readme",
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.0.0",
|
||||
"bookshelf": "^1.1.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"handlebars": "^4.7.6",
|
||||
"helmet": "^3.22.0",
|
||||
"jsonschema": "^1.2.6",
|
||||
"knex": "^0.21.1",
|
||||
"morgan": "^1.10.0",
|
||||
"mysql": "^2.18.1",
|
||||
"nodemailer": "^6.4.17",
|
||||
"uuid": "^8.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.18.0",
|
||||
"eslint-plugin-import": "^2.22.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"accessor-pairs": "warn",
|
||||
"array-callback-return": "error",
|
||||
"brace-style": "warn",
|
||||
"consistent-return": "error",
|
||||
"default-case": "error",
|
||||
"eqeqeq": "warn",
|
||||
"no-case-declarations": "error",
|
||||
"no-empty-pattern": "warn",
|
||||
"no-fallthrough": "error",
|
||||
"no-unused-vars": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-var": "error",
|
||||
"semi": "warn",
|
||||
"no-extra-semi": "error",
|
||||
"yoda": "warn"
|
||||
}
|
||||
}
|
||||
}
|
||||
206
api/repositories/ingredient-repository.js
Normal file
206
api/repositories/ingredient-repository.js
Normal file
@@ -0,0 +1,206 @@
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
const model = require('../models/ingredient-model');
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator;
|
||||
const validator = new Validator();
|
||||
const IngredientValidation = require("../validations/IngredientValidation");
|
||||
validator.addSchema(IngredientValidation, "/IngredientValidation");
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt;
|
||||
const isEmptyObject = require('../functions').isEmptyObject;
|
||||
|
||||
class IngredientRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.fetchAll({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Il n'existe aucun ingrédient disponible.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'ingrédient en question n'a pas pu être trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Les sortilèges liés à cet ingrédient n'ont pas pu être récupérés.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addOne(igr) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
if (isEmptyObject(igr)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(igr, IngredientValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle d'ingrédient n'est pas respecté : ${validator.validate(s, IngredientValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(igr.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return new model({
|
||||
'name': igr.name,
|
||||
'description': igr.description,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 (isEmptyObject(igr)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(igr, IngredientValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle d'ingrédient n'est pas respecté : ${validator.validate(s, IngredientValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(igr.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
new model({ id: id })
|
||||
.fetch({ require: true, withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': igr.name,
|
||||
'description': igr.description,
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'ingrédient en question n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ require: true, withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
v.spells().detach();
|
||||
v.destroy();
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'Ingredient with ID ' + id + ' successfully deleted !'
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'ingrédient en question n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IngredientRepository;
|
||||
51
api/repositories/meta-school-repository.js
Normal file
51
api/repositories/meta-school-repository.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Bookshelf
|
||||
const model = require('../models/meta-school-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const validator = new Validator()
|
||||
const MetaSchoolValidation = require("../validations/MetaSchoolValidation")
|
||||
validator.addSchema(MetaSchoolValidation, "/MetaSchoolValidation")
|
||||
|
||||
class MetaSchoolRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.fetchAll({ withRelated: ['schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject({
|
||||
"message": "Il n'existe aucune grande école disponible.",
|
||||
"code": 404
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject({
|
||||
"message": "La grande école en question n'a pas pu être trouvée.",
|
||||
"code": 404
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaSchoolRepository
|
||||
207
api/repositories/school-repository.js
Normal file
207
api/repositories/school-repository.js
Normal file
@@ -0,0 +1,207 @@
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
const model = require('../models/school-model');
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator;
|
||||
const validator = new Validator();
|
||||
const SchoolValidation = require("../validations/SchoolValidation");
|
||||
validator.addSchema(SchoolValidation, "/SchoolValidation");
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt;
|
||||
const isEmptyObject = require('../functions').isEmptyObject;
|
||||
|
||||
class SchoolRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.fetchAll({ withRelated: ['meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Il n'existe aucune école disponible.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'école en question n'a pas pu être trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Les sortilèges de cette école n'ont pas pu être récupérés.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addOne(s) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
if (isEmptyObject(s)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(s, SchoolValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle d'école n'est pas respecté : ${validator.validate(s, SchoolValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(s.name) || isXSSAttempt(s.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return new model({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'meta_school_id': s.meta_school_id,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['meta_schools']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 (isEmptyObject(s)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(s, SchoolValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle d'école n'est pas respecté : ${validator.validate(s, SchoolValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(s.name) || isXSSAttempt(s.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
new model({ id: id })
|
||||
.fetch({ require: true, withRelated: ['meta_schools'] })
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'meta_school_id': s.meta_school_id
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['meta_schools']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'école en question n'a pas été trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ require: true, withRelated: ['spells', 'meta_schools'] })
|
||||
.then(v => {
|
||||
v.spells().detach();
|
||||
v.destroy();
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'School with ID ' + id + ' successfully deleted !'
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "L'école en question n'a pas été trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SchoolRepository;
|
||||
351
api/repositories/spell-repository.js
Normal file
351
api/repositories/spell-repository.js
Normal file
@@ -0,0 +1,351 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/spell-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const validator = new Validator()
|
||||
const SpellValidation = require("../validations/SpellValidation")
|
||||
validator.addSchema(SpellValidation, "/SpellValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
class SpellRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll(name, description, level, charge, cost, ritual) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let query = new model();
|
||||
|
||||
if (name) {
|
||||
query.where('name', 'like', `%${name}%`)
|
||||
}
|
||||
if (description) {
|
||||
query.where('description', 'like', `%${description}%`)
|
||||
}
|
||||
if (level) {
|
||||
query.where({ 'level': level })
|
||||
}
|
||||
if (charge) {
|
||||
query.where({ 'charge': charge })
|
||||
}
|
||||
if (cost) {
|
||||
query.where({ 'cost': cost })
|
||||
}
|
||||
if (ritual) {
|
||||
query.where({ 'is_ritual': ritual })
|
||||
}
|
||||
|
||||
query.fetchAll({ withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Il n'existe aucun sortilège disponible.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getAllPublic(name, description, level, charge, cost, ritual) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let query = new model().where({ 'public': 1 })
|
||||
|
||||
if (name) {
|
||||
query.where('name', 'like', `%${name}%`)
|
||||
}
|
||||
if (description) {
|
||||
query.where('description', 'like', `%${description}%`)
|
||||
}
|
||||
if (level) {
|
||||
query.where({ 'level': level })
|
||||
}
|
||||
if (charge) {
|
||||
query.where({ 'charge': charge })
|
||||
}
|
||||
if (cost) {
|
||||
query.where({ 'cost': cost })
|
||||
}
|
||||
if (ritual) {
|
||||
query.where({ 'is_ritual': ritual })
|
||||
}
|
||||
|
||||
query.fetchAll({ withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Il n'existe aucun sortilège disponible.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getPage(page) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'public': 1 })
|
||||
.fetchPage({
|
||||
pageSize: 20,
|
||||
page: page,
|
||||
withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'],
|
||||
})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "La page de sortilèges n'a pas pu être chargée",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Le sortilège en question n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addOne(s) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
if (isEmptyObject(s)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(s, SpellValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle de sortilège n'est pas respecté : ${validator.validate(s, SpellValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return new model({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'level': s.level,
|
||||
'charge': s.charge,
|
||||
'cost': s.cost,
|
||||
'is_ritual': s.is_ritual
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.schools()
|
||||
.attach(s.schools, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.variables()
|
||||
.attach(s.variables, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.ingredients()
|
||||
.attach(s.ingredients, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Un attributs du sortilège a provoqué une erreur d'insertion.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['schools.meta_schools', 'variables', 'ingredients', 'author'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Le sortilège n'a pas pu être ajouté.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 (isEmptyObject(s)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(s, SpellValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle de sortilège n'est pas respecté : ${validator.validate(s, SpellValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
new model({ id: id })
|
||||
.fetch({ require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'] })
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'level': s.level,
|
||||
'charge': s.charge,
|
||||
'cost': s.cost,
|
||||
'is_ritual': s.is_ritual
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
// Detaches AND attaches pivot tables, dw about it
|
||||
.tap(spell => {
|
||||
if (s.schools) {
|
||||
let schools = spell.related('school');
|
||||
return spell.schools().detach(schools, { transacting: t });
|
||||
}
|
||||
return spell
|
||||
})
|
||||
.tap(spell => {
|
||||
if (s.variables) {
|
||||
let variables = spell.related('variable');
|
||||
return spell.variables().detach(variables, { transacting: t });
|
||||
}
|
||||
return spell;
|
||||
})
|
||||
.tap(spell => {
|
||||
if (s.ingredients) {
|
||||
let ingredients = spell.related('ingredient');
|
||||
return spell.ingredients().detach(ingredients, { transacting: t });
|
||||
}
|
||||
return spell;
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.schools()
|
||||
.attach(s.schools, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.variables()
|
||||
.attach(s.variables, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.ingredients()
|
||||
.attach(s.ingredients, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Un attributs du sortilège a provoqué une erreur d'insertion.",
|
||||
"code": 500,
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['schools.meta_schools', 'variables', 'ingredients', 'author']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur de chargement est survenue.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Le sortilège en question n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients', 'author'] })
|
||||
.then(v => {
|
||||
v.schools().detach();
|
||||
v.variables().detach();
|
||||
v.ingredients().detach();
|
||||
v.destroy();
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
"message": `Le sortilège #${id} a été supprimé avec succès.`,
|
||||
"code": 200,
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Le sortilège en question n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SpellRepository
|
||||
562
api/repositories/user-repository.js
Normal file
562
api/repositories/user-repository.js
Normal file
@@ -0,0 +1,562 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
const model = require('../models/user-model');
|
||||
const token_model = require('../models/api-token-model');
|
||||
|
||||
// Hashing and passwords
|
||||
const bcrypt = require('bcrypt');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
// Mailing methods
|
||||
const mails = require('../smtp/mails');
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator;
|
||||
const validator = new Validator();
|
||||
const UserValidation = require("../validations/UserValidation");
|
||||
validator.addSchema(UserValidation, "/UserValidation");
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt;
|
||||
const isEmptyObject = require('../functions').isEmptyObject;
|
||||
|
||||
class UserRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all users in the dabatase.
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: Array of user objects.
|
||||
*/
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.fetchAll({ withRelated: ['role.permissions'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject({
|
||||
"message": "Erreur de base de données, les utilisateurs n'ont pas pu être récupérés.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a user object associated with the uuid.
|
||||
*
|
||||
* @param { string } uuid
|
||||
* @param { boolean } full
|
||||
* Whether the password should also be fetched. (should never be true unless you want to log the user)
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: Queried user object.
|
||||
*/
|
||||
getOneByUUID(uuid, full) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (!(uuid)) {
|
||||
reject({
|
||||
"message": "La requête doit renseigner un uuid.",
|
||||
"code": 400,
|
||||
})
|
||||
}
|
||||
|
||||
new model()
|
||||
.where({ 'uuid': uuid })
|
||||
.fetch({ withRelated: ['role.permissions'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true, visibility: !full }));
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "L'utilisateur avec cet UUID n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a user object associated with the mail address.
|
||||
*
|
||||
* @param { string } mail
|
||||
* @param { boolean } full
|
||||
* Whether the password should also be fetched. (should never be true unless you want to log the user)
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: Queried user object.
|
||||
*/
|
||||
getOneByEmail(mail, full) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (!(mail)) {
|
||||
reject({
|
||||
"message": "La requête doit renseigner un email.",
|
||||
"code": 400,
|
||||
})
|
||||
}
|
||||
|
||||
new model()
|
||||
.where({ 'mail': mail })
|
||||
.fetch({ withRelated: ['role'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true, visibility: !full }));
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "L'utilisateur avec cet email n'a pas été trouvé.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all spells linked to a user's uuid
|
||||
*
|
||||
* @param { string } uuid
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
getSpellsFromOne(uuid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (!(uuid)) {
|
||||
reject({
|
||||
"message": "La requête doit renseigner un uuid.",
|
||||
"code": 400,
|
||||
})
|
||||
}
|
||||
|
||||
new model()
|
||||
.where({ 'uuid': uuid })
|
||||
.fetch({ withRelated: ['role', 'spells.schools.meta_schools', 'spells.variables', 'spells.ingredients'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "Les sorts liés à cet utilisateur n'ont pas été trouvés.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a user based on the model at ./models/user-model.js.
|
||||
*
|
||||
* @param { object} u
|
||||
* User object
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: Queried user object.
|
||||
*/
|
||||
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({
|
||||
"message": "Le corps de requête ne peut être vide.",
|
||||
"code": 403,
|
||||
})
|
||||
} else if (!validator.validate(u, UserValidation).valid) {
|
||||
reject({
|
||||
"message": "Structure de la requête invalide - " + validator.validate(u, UserValidation).errors,
|
||||
"code": 403,
|
||||
})
|
||||
} else if (isXSSAttempt(u.name) || isXSSAttempt(u.password) || isXSSAttempt(u.mail)) {
|
||||
reject({
|
||||
"message": "Essai d'injection détecté, avortement de la requête.",
|
||||
"code": 403,
|
||||
})
|
||||
} else {
|
||||
let hash = await bcrypt.hash(u.password, 10);
|
||||
|
||||
let uuid = uuidv4();
|
||||
let verification_token = uuidv4();
|
||||
|
||||
this.checkIfEmailAvailable(u.mail)
|
||||
.then(() => {
|
||||
bookshelf.transaction(t => {
|
||||
return new model({
|
||||
'uuid': uuid,
|
||||
'name': u.name,
|
||||
'mail': u.mail,
|
||||
'password': hash,
|
||||
'verification_token': verification_token,
|
||||
})
|
||||
.save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Un attribut de l'utilisateur a provoqué une erreur d'insertion.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
return this.getOneByUUID(uuid, false)
|
||||
})
|
||||
.then(newUser => {
|
||||
|
||||
// Send a mail to the new user's email with a link to verification url
|
||||
mails.sendRegistrationMail({
|
||||
user: {
|
||||
name: newUser.name,
|
||||
mail: newUser.mail,
|
||||
token: verification_token,
|
||||
}
|
||||
});
|
||||
|
||||
// Then resolves the api call
|
||||
resolve({
|
||||
"message": `Compte utilisateur #${newUser.id} créé avec succès.`,
|
||||
"code": 201,
|
||||
"user": newUser,
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
resolve({
|
||||
"message": "Une erreur s'est produite en créant votre compte. Veuillez réessayer ultérieurement ou contactez l'administrateur.",
|
||||
"code": 500,
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies an account based on a private UUID token
|
||||
*
|
||||
* @param { string } token
|
||||
* A UUID v4 identification token provided at registration and on special demands
|
||||
*
|
||||
* @returns Redirects to login page
|
||||
*/
|
||||
verifyUser(token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'verification_token': token })
|
||||
.fetch()
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'verification_token': null,
|
||||
'verified': 1,
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
"message": "Insérez ici une future redirection vers le client.",
|
||||
"code": 202,
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "Le lien de vérification ne semble pas correct.",
|
||||
"code": 404,
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a user by comparing the dual mail/password inputs
|
||||
*
|
||||
* @param { string } mail
|
||||
* @param { string } password
|
||||
*
|
||||
* @return { Promise }
|
||||
* Fulfilled data: Queried user object.
|
||||
*/
|
||||
logUser(mail, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.getOneByEmail(mail, true)
|
||||
.then(async fetchedUser => {
|
||||
|
||||
let match = await bcrypt.compare(password, fetchedUser.password);
|
||||
|
||||
// Makes sure no hash gets out
|
||||
delete fetchedUser.password;
|
||||
|
||||
// If you found a user...
|
||||
if (match) {
|
||||
// If they're banned...
|
||||
if (fetchedUser.banned) {
|
||||
reject({
|
||||
"message": `L'utilisateur #${fetchedUser.name} a été banni, la connexion est impossible.`,
|
||||
"code": 403,
|
||||
});
|
||||
// If they're not verified...
|
||||
} else if (!fetchedUser.verified) {
|
||||
reject({
|
||||
"message": `L'utilisateur #${fetchedUser.name} n'as pas été vérifié, le compte doit être activé avant la connexion.`,
|
||||
"code": 401,
|
||||
});
|
||||
} else {
|
||||
resolve({
|
||||
"message": `L'utilisateur #${fetchedUser.name} s'est connecté.`,
|
||||
"code": 200,
|
||||
"user": fetchedUser,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
reject({
|
||||
"message": "Les informations de connexions sont erronées.",
|
||||
"code": 400,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a token for the user to use the API
|
||||
* Requires mail and password for verifying the user
|
||||
*
|
||||
* @param { string } mail
|
||||
* @param { string } password
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: A unique UUID token string.
|
||||
*/
|
||||
genAPIToken(mail, password) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.logUser(mail, password)
|
||||
.then(v => {
|
||||
let user = v.user;
|
||||
let new_token = uuidv4();
|
||||
|
||||
bookshelf.transaction(t => {
|
||||
return new token_model({
|
||||
'value': new_token,
|
||||
'user_uuid': user.uuid,
|
||||
})
|
||||
.save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
// If the account already has an API key linked...
|
||||
if (err.errno === 1062) {
|
||||
this.fetchAPIKey(user.uuid)
|
||||
.then(old_api_key => {
|
||||
reject({
|
||||
"message": "Votre compte a déjà généré une clé d'API.",
|
||||
"code": 409,
|
||||
"API_key": old_api_key.value,
|
||||
});
|
||||
});
|
||||
|
||||
// Default errors
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(api_key => {
|
||||
resolve({
|
||||
"message": "La clé d'API a été généré.",
|
||||
"code": 201,
|
||||
"API_key": api_key,
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "La génération de jeton d'API n'a pas pu être conclue.",
|
||||
"code": 500,
|
||||
});
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
checkAPITokenPerms(token, permissions) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
|
||||
// If the request doesn't have a token, reject it.
|
||||
if (!token) {
|
||||
reject({
|
||||
"message": "Vous devez utiliser un jeton d'API dans l'en-tête de votre requête.",
|
||||
"code": 401,
|
||||
})
|
||||
}
|
||||
|
||||
// Fetches user from token
|
||||
new token_model()
|
||||
.where({ 'value': token })
|
||||
.fetch({ withRelated: 'user.role.permissions' })
|
||||
|
||||
// Catches not found errors
|
||||
.catch(err => {
|
||||
if (err instanceof token_model.NotFoundError) {
|
||||
reject({
|
||||
"message": "Ce jeton n'est affilié à aucun compte.",
|
||||
"code": 404,
|
||||
});
|
||||
} else {
|
||||
reject({
|
||||
"message": "Le jeton ou l'utilisateur n'a pas pu être récupéré.",
|
||||
"code": 500,
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
.then(fullToken => {
|
||||
token = fullToken.toJSON({ omitPivot: true });
|
||||
|
||||
// If the token is associated with a banned user...
|
||||
if (token.user.banned) {
|
||||
reject({
|
||||
"message": "Le jeton est lié à un utilisateur banni, il n'est donc plus utilisable.",
|
||||
"code": 401,
|
||||
});
|
||||
}
|
||||
|
||||
// If the token is associated with a non-verified user...
|
||||
if (!token.user.verified) {
|
||||
reject({
|
||||
"message": "Le jeton est lié à un utilisateur non-vérifié, il n'est donc pas utilisable.",
|
||||
"code": 401,
|
||||
});
|
||||
}
|
||||
|
||||
let user_permissions = token.user.role.permissions;
|
||||
|
||||
// Convert user_perm to array
|
||||
user_permissions.forEach((user_perm, i) => {
|
||||
user_permissions[i] = user_perm.slug;
|
||||
});
|
||||
|
||||
// Loops to check if the person has all the permissions required...
|
||||
permissions.forEach(perm => {
|
||||
// If not, reject...
|
||||
if (!user_permissions.includes(perm)) {
|
||||
reject({
|
||||
"message": "Permissions insuffisantes.",
|
||||
"code": 401
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// If everything went well, resolve the promise.
|
||||
resolve({
|
||||
"message": "Credentials accepted.",
|
||||
"code": 200
|
||||
});
|
||||
})
|
||||
|
||||
// Unhandled errors
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "Une erreur inconnue est survenue.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the email that was input is available for account creation.
|
||||
*
|
||||
* @param {string} mail
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled: HTTP 200 if email is available.
|
||||
* Rejected: HTTP 400-409 if email is already used.
|
||||
*/
|
||||
checkIfEmailAvailable(mail) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (!(mail)) {
|
||||
reject({
|
||||
"message": "La requête doit renseigner un email.",
|
||||
"code": 400,
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.validateMail(mail)) {
|
||||
reject({
|
||||
"message": "La requête n'est pas un email valide.",
|
||||
"code": 400,
|
||||
})
|
||||
}
|
||||
|
||||
this.getOneByEmail(mail, false)
|
||||
.then(() => {
|
||||
reject({
|
||||
"message": "Cet email est déjà lié à un compte.",
|
||||
"code": 409,
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
resolve({
|
||||
"message": "Cet email est disponible.",
|
||||
"code": 200,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the associated api_token from a user uuid.
|
||||
*
|
||||
* @param { string } uuid
|
||||
*
|
||||
* @returns { Promise }
|
||||
* Fulfilled data: Queried API token object
|
||||
*/
|
||||
fetchAPIKey(uuid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new token_model()
|
||||
.where({ 'user_uuid': uuid })
|
||||
.fetch()
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a mail is correctly formed and ripe for receiving, ie: xxx@yyy.zzz.
|
||||
*
|
||||
* @param { string } mail
|
||||
*
|
||||
* @returns { boolean }
|
||||
*/
|
||||
validateMail(mail) {
|
||||
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return regex.test(String(mail).toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserRepository
|
||||
204
api/repositories/variable-repository.js
Normal file
204
api/repositories/variable-repository.js
Normal file
@@ -0,0 +1,204 @@
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf;
|
||||
const model = require('../models/variable-model');
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator;
|
||||
const validator = new Validator();
|
||||
const VariableValidation = require("../validations/VariableValidation");
|
||||
validator.addSchema(VariableValidation, "/VariableValidation");
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt;
|
||||
const isEmptyObject = require('../functions').isEmptyObject;
|
||||
|
||||
class VariableRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.fetchAll({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Il n'existe aucune variable disponible.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "La variable en question n'a pas pu être trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Les sortilèges liés à cette variable n'ont pas pu être récupérés.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addOne(vr) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
if (isEmptyObject(vr)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(vr, VariableValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle de variable n'est pas respecté : ${validator.validate(s, VariableValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(vr.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return new model({
|
||||
'description': vr.description,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 (isEmptyObject(vr)) {
|
||||
reject({
|
||||
"message": "Le corps de la requête ne peut pas être vide.",
|
||||
"code": 403,
|
||||
});
|
||||
} else if (!validator.validate(vr, VariableValidation).valid) {
|
||||
reject({
|
||||
"message": `Le modèle de variable n'est pas respecté : ${validator.validate(s, VariableValidation).errors}`,
|
||||
"code": 403,
|
||||
});
|
||||
} else if (isXSSAttempt(vr.description)) {
|
||||
reject({
|
||||
"message": "Tentative d'injection XSS détectée, requête refusée.",
|
||||
"code": 403,
|
||||
});
|
||||
} else {
|
||||
new model({ id: id })
|
||||
.fetch({ require: true, withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'description': vr.description,
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells']);
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "Une erreur d'insertion s'est produite.",
|
||||
"code": 500,
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "La variable en question n'a pas été trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new model()
|
||||
.where({ 'id': id })
|
||||
.fetch({ require: true, withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
v.spells().detach();
|
||||
v.destroy();
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'Variable with ID ' + id + ' successfully deleted !'
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reject({
|
||||
"message": "La variable en question n'a pas été trouvée.",
|
||||
"code": 404,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VariableRepository;
|
||||
28
api/routes/auth.js
Normal file
28
api/routes/auth.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// Repository
|
||||
const UserRepository = require('../repositories/user-repository');
|
||||
const Users = new UserRepository();
|
||||
|
||||
// ROUTES
|
||||
// GEN API TOKEN
|
||||
const generateAPIToken = (mail, password) => {
|
||||
return Users.genAPIToken(mail, password)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/genToken', async (req, res) => {
|
||||
generateAPIToken(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(err));
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
18
api/routes/index.js
Normal file
18
api/routes/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const spells = require('./spells');
|
||||
const schools = require('./schools');
|
||||
const meta_schools = require('./meta_schools');
|
||||
const variables = require('./variables');
|
||||
const ingredients = require('./ingredients');
|
||||
const users = require('./users');
|
||||
|
||||
const auth = require('./auth');
|
||||
|
||||
module.exports = {
|
||||
auth,
|
||||
spells,
|
||||
schools,
|
||||
meta_schools,
|
||||
ingredients,
|
||||
variables,
|
||||
users,
|
||||
};
|
||||
183
api/routes/ingredients.js
Normal file
183
api/routes/ingredients.js
Normal file
@@ -0,0 +1,183 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// AuthGuard
|
||||
const authGuard = require('./middleware/authGuard');
|
||||
|
||||
// Repository
|
||||
const IngredientRepository = require('../repositories/ingredient-repository');
|
||||
const Ingredients = new IngredientRepository();
|
||||
|
||||
// Functions
|
||||
const functions = require('../functions');
|
||||
|
||||
// ROUTES
|
||||
// GET ALL ------------------
|
||||
const getIngredients = () => {
|
||||
return Ingredients.getAll()
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/',
|
||||
async (req, res) => {
|
||||
getIngredients()
|
||||
.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 getIngredient = (id) => {
|
||||
return Ingredients.getOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/',
|
||||
async (req, res) => {
|
||||
getIngredient(req.params.id)
|
||||
.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 SPELLS FROM ONE ------------------
|
||||
const getSpellsFromOne = (id) => {
|
||||
return Ingredients.getSpellsFromOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/spells',
|
||||
async (req, res) => {
|
||||
getSpellsFromOne(req.params.id)
|
||||
.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 addIngredient = (igr) => {
|
||||
return Ingredients.addOne(igr)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.post(
|
||||
'/',
|
||||
authGuard(['SUBMIT_INGREDIENTS']),
|
||||
async (req, res) => {
|
||||
addIngredient(req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// UPDATE ONE ------------------
|
||||
const updateIngredient = (id, igr) => {
|
||||
return Ingredients.updateOne(id, igr)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.put(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_INGREDIENTS', 'MODIFY_INGREDIENTS']),
|
||||
async (req, res) => {
|
||||
updateIngredient(req.params.id, req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// DELETE ONE ------------------
|
||||
const deleteIngredient = (id) => {
|
||||
return Ingredients.deleteOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.delete(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_INGREDIENTS', 'MODIFY_INGREDIENTS', 'DELETE_INGREDIENTS']),
|
||||
async (req, res) => {
|
||||
deleteIngredient(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 validations
|
||||
router.param('id', functions.paramIntCheck);
|
||||
|
||||
module.exports = router;
|
||||
65
api/routes/meta_schools.js
Normal file
65
api/routes/meta_schools.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// Functions
|
||||
const functions = require('../functions');
|
||||
|
||||
// Repository
|
||||
const MetaSchoolRepository = require('../repositories/meta-school-repository');
|
||||
const MetaSchools = new MetaSchoolRepository();
|
||||
|
||||
// ROUTES
|
||||
// GET ALL ------------------
|
||||
const getMetaSchools = () => {
|
||||
return MetaSchools.getAll()
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/', async (req, res) => {
|
||||
getMetaSchools()
|
||||
.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 getMetaSchool = (id) => {
|
||||
return MetaSchools.getOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/:id/', async (req, res) => {
|
||||
getMetaSchool(req.params.id)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Param validations
|
||||
router.param('id', functions.paramIntCheck);
|
||||
|
||||
module.exports = router;
|
||||
23
api/routes/middleware/authGuard.js
Normal file
23
api/routes/middleware/authGuard.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// Repository
|
||||
const UserRepository = require('../../repositories/user-repository');
|
||||
const Users = new UserRepository();
|
||||
|
||||
// AUTHGUARD
|
||||
const authGuard = (permissions) => {
|
||||
return async (req, res, next) => {
|
||||
|
||||
// Get token from headers
|
||||
let api_token = req.headers['auracle_key'];
|
||||
|
||||
// Uses repo to validate the associated perms with the token
|
||||
Users.checkAPITokenPerms(api_token, permissions)
|
||||
.then(() => {
|
||||
next();
|
||||
})
|
||||
.catch(err => {
|
||||
res.status(err.code).send(JSON.stringify(err));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = authGuard;
|
||||
182
api/routes/schools.js
Normal file
182
api/routes/schools.js
Normal file
@@ -0,0 +1,182 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// AuthGuard
|
||||
const authGuard = require('./middleware/authGuard');
|
||||
|
||||
// Repository
|
||||
const SchoolRepository = require('../repositories/school-repository');
|
||||
const Schools = new SchoolRepository();
|
||||
|
||||
// Functions
|
||||
const functions = require('../functions');
|
||||
|
||||
// ROUTES
|
||||
// GET ALL ------------------
|
||||
const getSchools = () => {
|
||||
return Schools.getAll()
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/',
|
||||
async (req, res) => {
|
||||
getSchools()
|
||||
.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 getSchool = (id) => {
|
||||
return Schools.getOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/',
|
||||
async (req, res) => {
|
||||
getSchool(req.params.id)
|
||||
.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 SPELLS FROM ONE ------------------
|
||||
const getSpellsFromOne = (id) => {
|
||||
return Schools.getSpellsFromOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/spells',
|
||||
async (req, res) => {
|
||||
getSpellsFromOne(req.params.id)
|
||||
.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 addSchool = (s) => {
|
||||
return Schools.addOne(s)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.post(
|
||||
'/',
|
||||
authGuard(['SUBMIT_SCHOOL']),
|
||||
async (req, res) => {
|
||||
addSchool(req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// UPDATE ONE ------------------
|
||||
const updateSchool = (id, s) => {
|
||||
return Schools.updateOne(id, s)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.put(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_SCHOOLS', 'MODIFY_SCHOOLS']),
|
||||
async (req, res) => {
|
||||
updateSchool(req.params.id, req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// DELETE ONE ------------------
|
||||
const deleteSchool = (id) => {
|
||||
return Schools.deleteOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.delete(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_SCHOOLS', 'MODIFY_SCHOOLS', 'DELETE_SCHOOLS']),
|
||||
async (req, res) => {
|
||||
deleteSchool(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 validations
|
||||
router.param('id', functions.paramIntCheck);
|
||||
|
||||
module.exports = router;
|
||||
209
api/routes/spells.js
Normal file
209
api/routes/spells.js
Normal file
@@ -0,0 +1,209 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// AuthGuard
|
||||
const authGuard = require('./middleware/authGuard');
|
||||
|
||||
// Repository
|
||||
const SpellReposity = require('../repositories/spell-repository');
|
||||
const Spells = new SpellReposity();
|
||||
|
||||
// Functions
|
||||
const functions = require('../functions');
|
||||
|
||||
// ROUTES
|
||||
// GET ALL PUBLIC ------------------
|
||||
const getPublicSpells = (name, description, level, charge, cost, ritual) => {
|
||||
return Spells.getAllPublic(name, description, level, charge, cost, ritual)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'//:name?/:description?/:level?/:charge?/:cost?/:ritual?/',
|
||||
async (req, res) => {
|
||||
getPublicSpells(req.query.name, req.query.description, req.query.level, req.query.charge, req.query.cost, req.query.ritual)
|
||||
.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 = (name, description, level, charge, cost, ritual) => {
|
||||
return Spells.getAll(name, description, level, charge, cost, ritual)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/private/:name?/:description?/:level?/:charge?/:cost?/:ritual?/',
|
||||
authGuard(['SECRET_SPELLS']),
|
||||
async (req, res) => {
|
||||
getSpells(req.query.name, req.query.description, req.query.level, req.query.charge, req.query.cost, req.query.ritual)
|
||||
.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 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) => {
|
||||
return Spells.getOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/',
|
||||
async (req, res) => {
|
||||
getSpell(req.params.id)
|
||||
.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 addSpell = (s) => {
|
||||
return Spells.addOne(s)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.post(
|
||||
'/',
|
||||
authGuard(['SUBMIT_SPELLS']),
|
||||
async (req, res) => {
|
||||
addSpell(req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// UPDATE ONE ------------------
|
||||
const updateSpell = (id, s) => {
|
||||
return Spells.updateOne(id, s)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.put(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_SPELLS', 'MODIFY_SPELLS']),
|
||||
async (req, res) => {
|
||||
updateSpell(req.params.id, req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// DELETE ONE ------------------
|
||||
const deleteSpell = (id) => {
|
||||
return Spells.deleteOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.delete(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_SPELLS', 'MODIFY_SPELLS', 'DELETE_SPELLS']),
|
||||
async (req, res) => {
|
||||
deleteSpell(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 validations
|
||||
router.param('id', functions.paramIntCheck);
|
||||
router.param('page', functions.paramIntCheck);
|
||||
|
||||
module.exports = router;
|
||||
178
api/routes/users.js
Normal file
178
api/routes/users.js
Normal file
@@ -0,0 +1,178 @@
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// AuthGuard
|
||||
// const authGuard = require('./middleware/authGuard');
|
||||
|
||||
// Repository
|
||||
const UserRepository = require('../repositories/user-repository');
|
||||
const Users = new UserRepository();
|
||||
|
||||
// ROUTES
|
||||
// GET ALL ------------------
|
||||
const getUsers = () => {
|
||||
return Users.getAll()
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/', async (req, res) => {
|
||||
getUsers()
|
||||
.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 FROM UUID ------------------
|
||||
const getUserByUUID = (uuid) => {
|
||||
return Users.getOneByUUID(uuid)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/:uuid/', async (req, res) => {
|
||||
getUserByUUID(req.params.uuid)
|
||||
.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 SPELLS FROM ONE ------------------
|
||||
const getSpellsFromUser = (uuid) => {
|
||||
return Users.getSpellsFromOne(uuid)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/:uuid/spells', async (req, res) => {
|
||||
getSpellsFromUser(req.params.uuid)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// CHECK IF MAIL IS AVAILABLE ------------------
|
||||
const checkIfEmailAvailable = (mail) => {
|
||||
return Users.checkIfEmailAvailable(mail)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/available/:mail/', async (req, res) => {
|
||||
checkIfEmailAvailable(req.params.mail)
|
||||
.then(v => {
|
||||
res.setHeader('Content-Type', 'application/json;charset=utf-8');
|
||||
res.end(JSON.stringify(v));
|
||||
})
|
||||
.catch(err => {
|
||||
res.status(err.code).send(JSON.stringify(
|
||||
{
|
||||
"error": err.message,
|
||||
"code": err.code
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// CREATE ONE ------------------
|
||||
const addUser = (u) => {
|
||||
return Users.addOne(u)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.post('/', async (req, res) => {
|
||||
addUser(req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// VERIFY A USER
|
||||
const verifyUser = (token) => {
|
||||
return Users.verifyUser(token)
|
||||
.catch(err => {
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get('/verification/:token', async (req, res) => {
|
||||
verifyUser(req.params.token)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// LOG A USER ------------------
|
||||
const logUser = (mail, password) => {
|
||||
return Users.logUser(mail, password)
|
||||
.catch(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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
185
api/routes/variables.js
Normal file
185
api/routes/variables.js
Normal file
@@ -0,0 +1,185 @@
|
||||
'use strict';
|
||||
|
||||
// Router
|
||||
const express = require('express');
|
||||
let router = express.Router();
|
||||
|
||||
// AuthGuard
|
||||
const authGuard = require('./middleware/authGuard');
|
||||
|
||||
// Repository
|
||||
const VariableRepository = require('../repositories/variable-repository');
|
||||
const Variables = new VariableRepository();
|
||||
|
||||
// Functions
|
||||
const functions = require('../functions');
|
||||
|
||||
// ROUTES
|
||||
// GET ALL ------------------
|
||||
const getvariables = () => {
|
||||
return Variables.getAll()
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/',
|
||||
async (req, res) => {
|
||||
getvariables()
|
||||
.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 getVariable = (id) => {
|
||||
return Variables.getOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/',
|
||||
async (req, res) => {
|
||||
getVariable(req.params.id)
|
||||
.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 SPELLS FROM ONE ------------------
|
||||
const getSpellsFromOne = (id) => {
|
||||
return Variables.getSpellsFromOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.get(
|
||||
'/:id/spells',
|
||||
async (req, res) => {
|
||||
getSpellsFromOne(req.params.id)
|
||||
.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 addVariable = (vr) => {
|
||||
return Variables.addOne(vr)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.post(
|
||||
'/',
|
||||
authGuard(['SUBMIT_VARIABLES']),
|
||||
async (req, res) => {
|
||||
addVariable(req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// UPDATE ONE ------------------
|
||||
const updateVariable = (id, vr) => {
|
||||
return Variables.updateOne(id, vr)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.put(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_VARIABLES', 'MODIFY_VARIABLES']),
|
||||
async (req, res) => {
|
||||
updateVariable(req.params.id, req.body)
|
||||
.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
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// DELETE ONE ------------------
|
||||
const deleteVariable = (id) => {
|
||||
return Variables.deleteOne(id)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
router.delete(
|
||||
'/:id/',
|
||||
authGuard(['SUBMIT_VARIABLES', 'MODIFY_VARIABLES', 'DELETE_VARIABLES']),
|
||||
async (req, res) => {
|
||||
deleteVariable(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 validations
|
||||
router.param('id', functions.paramIntCheck);
|
||||
|
||||
module.exports = router;
|
||||
14
api/smtp/config.js
Normal file
14
api/smtp/config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const nodemailer = require('nodemailer');
|
||||
|
||||
const transport = nodemailer.createTransport({
|
||||
host: "smtp.mailtrap.io",
|
||||
port: 2525,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
transport,
|
||||
};
|
||||
61
api/smtp/mails.js
Normal file
61
api/smtp/mails.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const smtp = require('./config');
|
||||
const fs = require('fs');
|
||||
const handlebars = require('handlebars');
|
||||
|
||||
// Sender address for mail service
|
||||
const sender = 'tymos@auracle.io';
|
||||
|
||||
// Fetches a HTML template file for parsing
|
||||
const getTemplateFile = (path) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(path, { encoding: 'utf-8' }, (err, html) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(html);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* SEND REGISTRATION MAIL FUNCTION
|
||||
* @param {Object} data
|
||||
* - user
|
||||
* - name
|
||||
* - mail
|
||||
* - token
|
||||
*/
|
||||
const sendRegistrationMail = (data) => {
|
||||
getTemplateFile(__dirname + '/templates/template-sign-up.html')
|
||||
.then(html => {
|
||||
let template = handlebars.compile(html);
|
||||
let template_parsed = template(data);
|
||||
|
||||
let message = {
|
||||
from: sender,
|
||||
to: data.user.mail,
|
||||
subject: 'Inscription Auracle.io',
|
||||
html: template_parsed,
|
||||
};
|
||||
|
||||
smtp.transport.sendMail(message, (err, info) => {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
console.log(info);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// const sendBanEmail = (date) => {
|
||||
// return null;
|
||||
// };
|
||||
|
||||
module.exports = {
|
||||
sendRegistrationMail,
|
||||
};
|
||||
114
api/smtp/templates/template-sign-up.html
Normal file
114
api/smtp/templates/template-sign-up.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Template Email Auracle Inscription</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&family=Playfair+Display:wght@700;800;900&display=swap');
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--black: 52, 58, 64;
|
||||
--white: #FFF;
|
||||
--primary: 89, 158, 244;
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--black));
|
||||
font-family: 'Lato', sans-serif;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.display {
|
||||
font-family: 'Playfair Display', serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
p:not(:last-child) {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.italics {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
position: relative;
|
||||
padding: 10vh 5vw;
|
||||
background: url('https://i.imgur.com/IxEKKEY.png') center center fixed repeat;
|
||||
}
|
||||
|
||||
.wrapper:before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 120px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgb(var(--primary));
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
background-color: var(--white);
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
header,
|
||||
footer {
|
||||
text-align: center;
|
||||
color: var(--white);
|
||||
background-color: rgb(var(--black));
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1 class="display">Bienvenue sur Auracle, {{ user.name }}!</h1>
|
||||
</header>
|
||||
<main>
|
||||
<p>Votre compte Auracle a bien été enregistré et est rattaché à cette adresse mail.</p>
|
||||
<p>Cependant, afin de garantir la sécurité de vos données, votre compte doit être vérifié avant votre
|
||||
première connexion. Vous pouvez
|
||||
<a href="http://localhost:2814/api/v1/users/verification/{{ user.token }}">
|
||||
suivre ce lien afin de confirmer votre inscription.
|
||||
</a>
|
||||
</p>
|
||||
<p>Si vous rencontrez des problèmes, n'hésitez pas à envoyer un mail à
|
||||
<a href="mailto:support@auracle.io">
|
||||
support@auracle.io
|
||||
</a>
|
||||
</p>
|
||||
<p><strong>Merci de votre soutien !</strong></p>
|
||||
<p class="italics">Bien sincèrement, Izàc Tymos.</p>
|
||||
</main>
|
||||
<footer>
|
||||
<div class="icon">
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -6,6 +6,6 @@ const Ingredient = {
|
||||
"description": { "type": "string" }
|
||||
},
|
||||
"required": ["name", "description"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Ingredient
|
||||
module.exports = Ingredient;
|
||||
@@ -7,6 +7,6 @@ const MetaSchool = {
|
||||
"schools": { "type": "array" }
|
||||
},
|
||||
"required": ["name", "description"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = MetaSchool
|
||||
module.exports = MetaSchool;
|
||||
@@ -7,6 +7,6 @@ const School = {
|
||||
"meta_school_id": { "type": "number" },
|
||||
},
|
||||
"required": ["name", "description", "meta_school_id"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = School
|
||||
module.exports = School;
|
||||
@@ -34,6 +34,6 @@ const Spell = {
|
||||
}
|
||||
},
|
||||
"required": ["name", "description"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Spell
|
||||
module.exports = Spell;
|
||||
@@ -7,6 +7,6 @@ const User = {
|
||||
"password": { "type": "string" },
|
||||
},
|
||||
"required": ["name", "password", "mail"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = User
|
||||
module.exports = User;
|
||||
@@ -5,6 +5,6 @@ const Variable = {
|
||||
"description": { "type": "string" },
|
||||
},
|
||||
"required": ["description"]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Variable
|
||||
module.exports = Variable;
|
||||
33
client/.eslintrc.json
Normal file
33
client/.eslintrc.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"ecmaFeatures": {
|
||||
"impliedStrict": true
|
||||
}
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-recommended",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {
|
||||
"indent": ["error", 2],
|
||||
"accessor-pairs": "warn",
|
||||
"array-callback-return": "error",
|
||||
"brace-style": "warn",
|
||||
"consistent-return": "error",
|
||||
"default-case": "error",
|
||||
"eqeqeq": "warn",
|
||||
"no-case-declarations": "error",
|
||||
"no-empty-pattern": "warn",
|
||||
"no-fallthrough": "error",
|
||||
"no-unused-vars": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-var": "error",
|
||||
"semi": "warn",
|
||||
"no-extra-semi": "error",
|
||||
"yoda": "warn"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
],
|
||||
}
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
],
|
||||
};
|
||||
|
||||
550
client/package-lock.json
generated
550
client/package-lock.json
generated
@@ -1333,12 +1333,36 @@
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
|
||||
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cacache": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz",
|
||||
@@ -1363,12 +1387,59 @@
|
||||
"rimraf": "^2.7.1",
|
||||
"ssri": "^7.0.0",
|
||||
"unique-filename": "^1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-collect": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
|
||||
"integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-flush": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
|
||||
"integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-pipeline": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
|
||||
"integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
|
||||
"integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aggregate-error": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"find-cache-dir": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.0.tgz",
|
||||
"integrity": "sha512-PtXtQb7IrD8O+h6Cq1dbpJH5NzD8+9keN1zZ0YlpDzl1PwXEJEBj6u1Xa92t1Hwluoozd9TNKul5Hi2iqpsWwg==",
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
|
||||
"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commondir": "^1.0.1",
|
||||
@@ -1386,6 +1457,12 @@
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
@@ -1396,9 +1473,9 @@
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz",
|
||||
"integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^6.0.0"
|
||||
@@ -1450,21 +1527,73 @@
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz",
|
||||
"integrity": "sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w==",
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz",
|
||||
"integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^13.0.1",
|
||||
"find-cache-dir": "^3.2.0",
|
||||
"jest-worker": "^25.1.0",
|
||||
"p-limit": "^2.2.2",
|
||||
"schema-utils": "^2.6.4",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"jest-worker": "^25.4.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"schema-utils": "^2.6.6",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^4.4.3",
|
||||
"terser": "^4.6.12",
|
||||
"webpack-sources": "^1.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"jest-worker": {
|
||||
"version": "25.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz",
|
||||
"integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"merge-stream": "^2.0.0",
|
||||
"supports-color": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"ajv": "^6.12.4",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||
"integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.6.1",
|
||||
"source-map-support": "~0.5.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1785,9 +1914,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"aggregate-error": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
|
||||
"integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
||||
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clean-stack": "^2.0.0",
|
||||
@@ -2111,34 +2240,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
}
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"babel-eslint": {
|
||||
@@ -3366,9 +3472,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"copy-webpack-plugin": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz",
|
||||
"integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
|
||||
"integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^12.0.3",
|
||||
@@ -3381,7 +3487,7 @@
|
||||
"normalize-path": "^3.0.0",
|
||||
"p-limit": "^2.2.1",
|
||||
"schema-utils": "^1.0.0",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"webpack-log": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -4270,9 +4376,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
|
||||
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
|
||||
"version": "6.5.3",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
|
||||
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.4.0",
|
||||
@@ -4485,12 +4591,11 @@
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/color-name": "^1.1.1",
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
@@ -4503,6 +4608,12 @@
|
||||
"restore-cursor": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"cli-width": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
|
||||
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
|
||||
"dev": true
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -4519,15 +4630,32 @@
|
||||
"dev": true
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
|
||||
"integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"esrecurse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"estraverse": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"figures": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||
@@ -4538,18 +4666,18 @@
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
|
||||
"integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
|
||||
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
|
||||
"integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
|
||||
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"type-fest": "^0.8.1"
|
||||
@@ -4562,9 +4690,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
|
||||
"integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parent-module": "^1.0.0",
|
||||
@@ -4572,30 +4700,30 @@
|
||||
}
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.6.tgz",
|
||||
"integrity": "sha512-7SVO4h+QIdMq6XcqIqrNte3gS5MzCCKZdsq9DO4PJziBFNYzP3PGFbDjgadDb//MCahzgjCxvQ/O2wa7kx9o4w==",
|
||||
"version": "7.3.3",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
|
||||
"integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^4.2.1",
|
||||
"chalk": "^3.0.0",
|
||||
"chalk": "^4.1.0",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"cli-width": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^3.0.0",
|
||||
"lodash": "^4.17.15",
|
||||
"lodash": "^4.17.19",
|
||||
"mute-stream": "0.0.8",
|
||||
"run-async": "^2.4.0",
|
||||
"rxjs": "^6.5.3",
|
||||
"rxjs": "^6.6.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"through": "^2.3.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@@ -4632,9 +4760,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"onetime": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
|
||||
"integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
@@ -4656,6 +4784,15 @@
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
|
||||
"integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
@@ -4702,9 +4839,9 @@
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
@@ -4732,14 +4869,50 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-vue": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-6.2.1.tgz",
|
||||
"integrity": "sha512-MiIDOotoWseIfLIfGeDzF6sDvHkVvGd2JgkvjyHtN3q4RoxdAXrAMuI3SXTOKatljgacKwpNAYShmcKZa4yZzw==",
|
||||
"version": "7.0.0-beta.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.0.0-beta.4.tgz",
|
||||
"integrity": "sha512-yb8Kki8b94a3A1sGum9TyVAkvPfKGPzWfZcXRmA2Tylt7TRi+b6mOtn1o6kM3NWatBs5gcGiCrH033DDPn0Msw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^2.1.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^5.6.0",
|
||||
"vue-eslint-parser": "^7.0.0"
|
||||
"semver": "^7.3.2",
|
||||
"vue-eslint-parser": "^7.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
|
||||
"integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
@@ -5299,9 +5472,9 @@
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
|
||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
|
||||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
|
||||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
@@ -5318,7 +5491,6 @@
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz",
|
||||
"integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.0.0"
|
||||
},
|
||||
@@ -5327,7 +5499,6 @@
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
@@ -5399,15 +5570,6 @@
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fs-write-stream-atomic": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
|
||||
@@ -7161,33 +7323,6 @@
|
||||
"integrity": "sha512-yV+gqbd5vaOYjqlbk16EG89xB5udgjqQF3C5FAORDg4f/IS1Yc5ERCv5e/57yBcfJYw05V5JyIXabhwb75Xxow==",
|
||||
"dev": true
|
||||
},
|
||||
"jest-worker": {
|
||||
"version": "25.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz",
|
||||
"integrity": "sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"merge-stream": "^2.0.0",
|
||||
"supports-color": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
|
||||
@@ -7490,9 +7625,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.defaultsdeep": {
|
||||
@@ -7859,33 +7994,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"minipass-collect": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
|
||||
"integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-flush": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
|
||||
"integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"minipass-pipeline": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz",
|
||||
"integrity": "sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"mississippi": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||
@@ -7951,8 +8059,7 @@
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"multicast-dns": {
|
||||
"version": "6.2.3",
|
||||
@@ -8046,14 +8153,14 @@
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
|
||||
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
|
||||
"dev": true
|
||||
},
|
||||
"node-gyp": {
|
||||
@@ -8642,15 +8749,6 @@
|
||||
"p-limit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
|
||||
"integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aggregate-error": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-retry": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
|
||||
@@ -10402,12 +10500,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"selfsigned": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
|
||||
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
|
||||
"version": "1.10.8",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
|
||||
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-forge": "0.9.0"
|
||||
"node-forge": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
@@ -10469,10 +10567,13 @@
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
||||
"dev": true
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
|
||||
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"serve-index": {
|
||||
"version": "1.9.1",
|
||||
@@ -11201,9 +11302,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
|
||||
"integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||
"dev": true
|
||||
},
|
||||
"stylehacks": {
|
||||
@@ -11911,9 +12012,9 @@
|
||||
"integrity": "sha512-Wg+ObZoYK6McHb5OOCFWvm0R7xHp0/p0G1ocx/8bO22jvA/yVY05rADbfiztwCokXBNfQuGv/XSd1ozcTFgekw=="
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
||||
"integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
|
||||
"integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==",
|
||||
"dev": true
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
@@ -11966,28 +12067,62 @@
|
||||
"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",
|
||||
"integrity": "sha512-yR0dLxsTT7JfD2YQo9BhnQ6bUTLsZouuzt9SKRP7XNaZJV459gvlsJo4vT2nhZ/2dH9j3c53bIx9dnqU2prM9g==",
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.3.0.tgz",
|
||||
"integrity": "sha512-n5PJKZbyspD0+8LnaZgpEvNCrjQx1DyDHw8JdWwoxhhC+yRip4TAvSDpXGf9SWX6b0umeB5aR61gwUo6NVvFxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"eslint-scope": "^5.0.0",
|
||||
"eslint-visitor-keys": "^1.1.0",
|
||||
"espree": "^6.1.2",
|
||||
"espree": "^6.2.1",
|
||||
"esquery": "^1.0.1",
|
||||
"lodash": "^4.17.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
|
||||
"integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"espree": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.1.1",
|
||||
"acorn-jsx": "^5.2.0",
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"esrecurse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"estraverse": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -12033,6 +12168,21 @@
|
||||
"vue": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"vue-meta": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-meta/-/vue-meta-2.4.0.tgz",
|
||||
"integrity": "sha512-XEeZUmlVeODclAjCNpWDnjgw+t3WA6gdzs6ENoIAgwO1J1d5p1tezDhtteLUFwcaQaTtayRrsx7GL6oXp/m2Jw==",
|
||||
"requires": {
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"deepmerge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
|
||||
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.1.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.1.6.tgz",
|
||||
|
||||
@@ -1,70 +1,59 @@
|
||||
{
|
||||
"name": "spellsaurus_client",
|
||||
"version": "1.0.0",
|
||||
"description": "The client interface of spellsaurus",
|
||||
"keywords": [
|
||||
"rpg",
|
||||
"dev",
|
||||
"spells",
|
||||
"roleplay",
|
||||
"website",
|
||||
"database"
|
||||
],
|
||||
"author": "AlexisNP",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/AlexisNP/spellsaurus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/AlexisNP/spellsaurus#readme",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/AlexisNP/spellsaurus.git"
|
||||
},
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.2",
|
||||
"bootstrap": "^4.5.0",
|
||||
"bootstrap-vue": "^2.15.0",
|
||||
"core-js": "^3.6.4",
|
||||
"jquery": "^3.5.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-cookies": "^1.7.0",
|
||||
"vue-masonry": "^0.11.8",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.2.0",
|
||||
"@vue/cli-plugin-eslint": "~4.2.0",
|
||||
"@vue/cli-service": "~4.2.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.1.2",
|
||||
"node-sass": "^4.14.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vue-router": "^3.1.6",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
"name": "spellsaurus_client",
|
||||
"version": "1.0.0",
|
||||
"description": "The client interface of spellsaurus",
|
||||
"keywords": [
|
||||
"rpg",
|
||||
"dev",
|
||||
"spells",
|
||||
"roleplay",
|
||||
"website",
|
||||
"database"
|
||||
],
|
||||
"author": "AlexisNP",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/AlexisNP/spellsaurus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/AlexisNP/spellsaurus#readme",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/AlexisNP/spellsaurus.git"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "vue-cli-service lint",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"bootstrap-vue": "^2.15.0",
|
||||
"core-js": "^3.6.4",
|
||||
"jquery": "^3.5.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"v-clipboard": "^2.2.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-cookies": "^1.7.0",
|
||||
"vue-masonry": "^0.11.8",
|
||||
"vue-meta": "^2.4.0",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.2.0",
|
||||
"@vue/cli-plugin-eslint": "~4.2.0",
|
||||
"@vue/cli-service": "~4.2.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-vue": "^7.0.0-beta.4",
|
||||
"node-sass": "^4.14.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vue-router": "^3.1.6",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
||||
|
||||
BIN
client/public/favicon.png
Normal file
BIN
client/public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -1,9 +1,9 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const url = process.env.VUE_APP_API_URL
|
||||
const url = process.env.VUE_APP_API_URL;
|
||||
|
||||
axios.defaults.headers.common[process.env.VUE_APP_API_KEY_NAME] = process.env.VUE_APP_API_KEY_VALUE
|
||||
axios.defaults.headers.common[process.env.VUE_APP_API_KEY_NAME] = process.env.VUE_APP_API_KEY_VALUE;
|
||||
|
||||
export default axios.create({
|
||||
baseURL: url
|
||||
})
|
||||
baseURL: url
|
||||
});
|
||||
@@ -1,12 +1,12 @@
|
||||
import api from './api'
|
||||
import api from './api';
|
||||
|
||||
const resource = "/ingredients"
|
||||
const resource = "/ingredients";
|
||||
|
||||
export default {
|
||||
getAll() {
|
||||
return api.get(`${resource}`)
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`)
|
||||
},
|
||||
}
|
||||
getAll() {
|
||||
return api.get(`${resource}`);
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`);
|
||||
},
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
import api from './api'
|
||||
import api from './api';
|
||||
|
||||
const resource = "/meta_schools"
|
||||
const resource = "/meta_schools";
|
||||
|
||||
export default {
|
||||
getAll() {
|
||||
return api.get(`${resource}`)
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`)
|
||||
},
|
||||
}
|
||||
getAll() {
|
||||
return api.get(`${resource}`);
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`);
|
||||
},
|
||||
};
|
||||
@@ -1,21 +1,21 @@
|
||||
import spellsRepository from './spellsRepository'
|
||||
import schoolsRepository from './schoolsRepository'
|
||||
import metaschoolsRepository from './metaschoolsRepository'
|
||||
import variablesRepository from './variablesRepository'
|
||||
import ingredientsRepository from './ingredientsRepository'
|
||||
import usersRepository from './usersRepository'
|
||||
import spellsRepository from './spellsRepository';
|
||||
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 = {
|
||||
spells: spellsRepository,
|
||||
schools: schoolsRepository,
|
||||
metaschools: metaschoolsRepository,
|
||||
variables: variablesRepository,
|
||||
ingredients: ingredientsRepository,
|
||||
users: usersRepository,
|
||||
}
|
||||
spells: spellsRepository,
|
||||
schools: schoolsRepository,
|
||||
metaschools: metaschoolsRepository,
|
||||
variables: variablesRepository,
|
||||
ingredients: ingredientsRepository,
|
||||
users: usersRepository,
|
||||
};
|
||||
|
||||
// Usage : RepositoryFactoryInstance.get('reponame');
|
||||
export const RepositoryFactory = {
|
||||
get: name => repositories[name]
|
||||
}
|
||||
get: name => repositories[name]
|
||||
};
|
||||
@@ -1,15 +1,15 @@
|
||||
import api from './api'
|
||||
import api from './api';
|
||||
|
||||
const resource = "/schools"
|
||||
const resource = "/schools";
|
||||
|
||||
export default {
|
||||
getAll() {
|
||||
return api.get(`${resource}`)
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`)
|
||||
},
|
||||
getSpellsFromOne(id) {
|
||||
return api.get(`${resource}/${id}/spells`)
|
||||
}
|
||||
}
|
||||
getAll() {
|
||||
return api.get(`${resource}`);
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`);
|
||||
},
|
||||
getSpellsFromOne(id) {
|
||||
return api.get(`${resource}/${id}/spells`);
|
||||
}
|
||||
};
|
||||
@@ -1,24 +1,24 @@
|
||||
import api from './api'
|
||||
import api from './api';
|
||||
|
||||
const resource = "/spells"
|
||||
const resource = "/spells";
|
||||
|
||||
export default {
|
||||
getAll() {
|
||||
return api.get(`${resource}`)
|
||||
},
|
||||
getPage(page) {
|
||||
return api.get(`${resource}/page/${page}`)
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`)
|
||||
},
|
||||
addOne(data) {
|
||||
return api.post(`${resource}`, data)
|
||||
},
|
||||
updateOne(id, data) {
|
||||
return api.put(`${resource}/${id}`, data)
|
||||
},
|
||||
deleteOne(id) {
|
||||
return api.delete(`${resource}/${id}`)
|
||||
}
|
||||
}
|
||||
getAll() {
|
||||
return api.get(`${resource}`);
|
||||
},
|
||||
getPage(page) {
|
||||
return api.get(`${resource}/page/${page}`);
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`);
|
||||
},
|
||||
addOne(data) {
|
||||
return api.post(`${resource}`, data);
|
||||
},
|
||||
updateOne(id, data) {
|
||||
return api.put(`${resource}/${id}`, data);
|
||||
},
|
||||
deleteOne(id) {
|
||||
return api.delete(`${resource}/${id}`);
|
||||
}
|
||||
};
|
||||
@@ -3,10 +3,16 @@ import api from './api'
|
||||
const resource = "/users"
|
||||
|
||||
export default {
|
||||
login(data) {
|
||||
return api.post(`${resource}/login`, data)
|
||||
},
|
||||
register(data) {
|
||||
return api.post(`${resource}`, data)
|
||||
},
|
||||
getOneFromUUID(uuid) {
|
||||
return api.get(`${resource}/${uuid}`,)
|
||||
},
|
||||
checkEmailAvailable(mail) {
|
||||
return api.get(`${resource}/available/${mail}`)
|
||||
},
|
||||
login(data) {
|
||||
return api.post(`${resource}/login`, data)
|
||||
},
|
||||
register(data) {
|
||||
return api.post(`${resource}`, data)
|
||||
},
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import api from './api'
|
||||
import api from './api';
|
||||
|
||||
const resource = "/variables"
|
||||
const resource = "/variables";
|
||||
|
||||
export default {
|
||||
getAll() {
|
||||
return api.get(`${resource}`)
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`)
|
||||
},
|
||||
}
|
||||
getAll() {
|
||||
return api.get(`${resource}`);
|
||||
},
|
||||
getOne(id) {
|
||||
return api.get(`${resource}/${id}`);
|
||||
},
|
||||
};
|
||||
@@ -1,21 +1,25 @@
|
||||
<template>
|
||||
<div id="srs">
|
||||
<header>
|
||||
<navbar/>
|
||||
</header>
|
||||
<router-view/>
|
||||
</div>
|
||||
<div id="srs">
|
||||
<header>
|
||||
<navbar />
|
||||
</header>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'app'
|
||||
}
|
||||
name: 'App',
|
||||
metaInfo: {
|
||||
title: 'Auracle',
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#srs {
|
||||
min-height: 100vh;
|
||||
background: url('./assets/images/bg1.png') center center fixed repeat;
|
||||
padding-top: 50px;
|
||||
min-height: 100vh;
|
||||
background: url('./assets/images/bg1.png') center center fixed repeat;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,3 @@
|
||||
// Other global files
|
||||
@import '_variables';
|
||||
@import '_fonts';
|
||||
|
||||
// RESETS
|
||||
html {
|
||||
font-size: $font-size-root;
|
||||
@@ -9,7 +5,7 @@ html {
|
||||
height: 100%;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
line-height: 1.15;
|
||||
color: $primary--base;
|
||||
color: $primary-base;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
* {
|
||||
@@ -42,10 +38,11 @@ hr {
|
||||
border-top-color: rgba($black, .25);
|
||||
}
|
||||
|
||||
// BOOTSTRAP
|
||||
// BOOTSTRAP OVERRIDES
|
||||
.nav-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-right: 5px;
|
||||
}
|
||||
@@ -53,6 +50,15 @@ hr {
|
||||
.word-break{ word-wrap: break-word; }
|
||||
.cursor-pointer{ cursor: pointer; }
|
||||
|
||||
.font-weight-black {
|
||||
font-weight: $heavy;
|
||||
}
|
||||
|
||||
// UTILITIES
|
||||
.prewrap {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
// LAYOUTS
|
||||
.fullpage {
|
||||
min-height: calc(100vh - 56px);
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
|
||||
//// COLOURS
|
||||
// Global colours
|
||||
$white: #FFF;
|
||||
$black: #000;
|
||||
$dull--black: #0D0D0D;
|
||||
$dull-black: #0D0D0D;
|
||||
|
||||
$primary--base: #2c3e50;
|
||||
$primary--blue: #599EF4;
|
||||
$secondary--blue: #355F91;
|
||||
$primary-base: #2c3e50;
|
||||
$primary-blue: #599EF4;
|
||||
$secondary-blue: #355F91;
|
||||
|
||||
$valid: #6AC47B;
|
||||
$warning: #F7A758;
|
||||
$alert: #F44E4E;
|
||||
|
||||
// Spell colours
|
||||
$spell-card--innerborder: #f5ebd8;
|
||||
|
||||
// FONT FAMILY BASES
|
||||
$font-family: 'Lato', sans-serif;
|
||||
$font-family: 'Lato', sans-serif !default;
|
||||
|
||||
$font-light: 300;
|
||||
$font-regular: 400;
|
||||
$font-bold: 700;
|
||||
$light: 300;
|
||||
$regular: 400;
|
||||
$bold: 700;
|
||||
$heavy: 900;
|
||||
|
||||
$font-size-root: 15px !default;
|
||||
$font-size-base: 1.2rem !default;
|
||||
$font-size-root: 16px !default;
|
||||
$font-size-base: 1rem !default;
|
||||
$line-height-base: 1.3 !default;
|
||||
|
||||
// Breakpoints
|
||||
$bp-sm: 576px;
|
||||
$bp-md: 768px;
|
||||
$bp-lg: 992px;
|
||||
$bp-xl: 1200px;
|
||||
@@ -1,110 +1,110 @@
|
||||
<template>
|
||||
<div class="lds-roller">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="lds-roller">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loader',
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
}
|
||||
}
|
||||
name: 'Loader',
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.lds-roller {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
div {
|
||||
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
transform-origin: 40px 40px;
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
margin: -4px 0 0 -4px;
|
||||
}
|
||||
&:nth-child(1) {
|
||||
animation-delay: -0.036s;
|
||||
&:after {
|
||||
top: 63px;
|
||||
left: 63px;
|
||||
}
|
||||
}
|
||||
&:nth-child(2) {
|
||||
animation-delay: -0.072s;
|
||||
&:after {
|
||||
top: 68px;
|
||||
left: 56px;
|
||||
}
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation-delay: -0.108s;
|
||||
&:after {
|
||||
top: 71px;
|
||||
left: 48px;
|
||||
}
|
||||
}
|
||||
&:nth-child(4) {
|
||||
animation-delay: -0.144s;
|
||||
&:after {
|
||||
top: 72px;
|
||||
left: 40px;
|
||||
}
|
||||
}
|
||||
&:nth-child(5) {
|
||||
animation-delay: -0.18s;
|
||||
&:after {
|
||||
top: 71px;
|
||||
left: 32px;
|
||||
}
|
||||
}
|
||||
&:nth-child(6) {
|
||||
animation-delay: -0.216s;
|
||||
&:after {
|
||||
top: 68px;
|
||||
left: 24px;
|
||||
}
|
||||
}
|
||||
&:nth-child(7) {
|
||||
animation-delay: -0.252s;
|
||||
&:after {
|
||||
top: 63px;
|
||||
left: 17px;
|
||||
}
|
||||
}
|
||||
&:nth-child(8) {
|
||||
animation-delay: -0.288s;
|
||||
&:after {
|
||||
top: 56px;
|
||||
left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
div {
|
||||
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
transform-origin: 40px 40px;
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: var(--primary);
|
||||
margin: -4px 0 0 -4px;
|
||||
}
|
||||
&:nth-child(1) {
|
||||
animation-delay: -0.036s;
|
||||
&:after {
|
||||
top: 63px;
|
||||
left: 63px;
|
||||
}
|
||||
}
|
||||
&:nth-child(2) {
|
||||
animation-delay: -0.072s;
|
||||
&:after {
|
||||
top: 68px;
|
||||
left: 56px;
|
||||
}
|
||||
}
|
||||
&:nth-child(3) {
|
||||
animation-delay: -0.108s;
|
||||
&:after {
|
||||
top: 71px;
|
||||
left: 48px;
|
||||
}
|
||||
}
|
||||
&:nth-child(4) {
|
||||
animation-delay: -0.144s;
|
||||
&:after {
|
||||
top: 72px;
|
||||
left: 40px;
|
||||
}
|
||||
}
|
||||
&:nth-child(5) {
|
||||
animation-delay: -0.18s;
|
||||
&:after {
|
||||
top: 71px;
|
||||
left: 32px;
|
||||
}
|
||||
}
|
||||
&:nth-child(6) {
|
||||
animation-delay: -0.216s;
|
||||
&:after {
|
||||
top: 68px;
|
||||
left: 24px;
|
||||
}
|
||||
}
|
||||
&:nth-child(7) {
|
||||
animation-delay: -0.252s;
|
||||
&:after {
|
||||
top: 63px;
|
||||
left: 17px;
|
||||
}
|
||||
}
|
||||
&:nth-child(8) {
|
||||
animation-delay: -0.288s;
|
||||
&:after {
|
||||
top: 56px;
|
||||
left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes lds-roller {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,56 +1,110 @@
|
||||
<template>
|
||||
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
|
||||
<router-link :to="'/'" class="navbar-brand font-display font-weight-700">Auracle</router-link>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbar">
|
||||
<ul class="navbar-nav mr-auto" v-if="links.length != 0">
|
||||
<li class="nav-item" v-for="(link, index) in links" :key="index">
|
||||
<router-link :to="link.url" class="nav-link">{{ link.text }}</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="user" class="navbar-nav">
|
||||
<router-link :to="'/profil'" class="nav-link">{{ user.name }}</router-link>
|
||||
<div @click="logoutUser()" class="nav-link">Deconnexion</div>
|
||||
</div>
|
||||
<div v-else class="navbar-nav">
|
||||
<router-link :to="'/connexion'" class="nav-link">Connexion</router-link>
|
||||
</div>
|
||||
<nav class="navbar navbar-expand-sm fixed-top navbar-dark bg-dark">
|
||||
<router-link
|
||||
:to="'/'"
|
||||
class="navbar-brand font-display font-weight-700"
|
||||
>
|
||||
Auracle
|
||||
</router-link>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-toggle="collapse"
|
||||
data-target="#navbar"
|
||||
aria-controls="navbar"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon" />
|
||||
</button>
|
||||
<div
|
||||
id="navbar"
|
||||
class="collapse navbar-collapse"
|
||||
>
|
||||
<ul
|
||||
v-if="links.length != 0"
|
||||
class="navbar-nav mr-auto"
|
||||
>
|
||||
<li
|
||||
v-for="(link, index) in links"
|
||||
:key="index"
|
||||
class="nav-item"
|
||||
>
|
||||
<router-link
|
||||
:to="link.url"
|
||||
class="nav-link"
|
||||
>
|
||||
{{ link.text }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<div
|
||||
v-if="user"
|
||||
class="navbar-nav"
|
||||
>
|
||||
<router-link
|
||||
:to="'/profil'"
|
||||
class="nav-link"
|
||||
>
|
||||
{{ user.name }}
|
||||
</router-link>
|
||||
<div
|
||||
class="nav-link"
|
||||
@click="logoutUser()"
|
||||
>
|
||||
Deconnexion
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="navbar-nav"
|
||||
>
|
||||
<router-link
|
||||
:to="'/connexion'"
|
||||
class="nav-link"
|
||||
>
|
||||
Connexion
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'navbar',
|
||||
data() {
|
||||
return {
|
||||
links: [
|
||||
{
|
||||
text: 'Sortilèges',
|
||||
url: '/sorts',
|
||||
},
|
||||
{
|
||||
text: 'Écoles',
|
||||
url: '/ecoles',
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Navbar',
|
||||
data() {
|
||||
return {
|
||||
links: [
|
||||
{
|
||||
text: 'Sortilèges',
|
||||
url: '/sorts',
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.state.user
|
||||
}
|
||||
{
|
||||
text: 'Écoles',
|
||||
url: '/ecoles',
|
||||
},
|
||||
methods: {
|
||||
logoutUser() {
|
||||
this.$cookies.remove('U_')
|
||||
this.$store.commit('logout')
|
||||
this.$router.push('/')
|
||||
}
|
||||
{
|
||||
text: 'Chronologie',
|
||||
url: '/ages',
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.getUserProfile;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
logoutUser() {
|
||||
this.$store.dispatch('user_logout');
|
||||
this.$router.push('/');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
||||
@@ -1,159 +1,297 @@
|
||||
<template>
|
||||
<b-modal
|
||||
<b-modal
|
||||
ref="add_spell_modal"
|
||||
size="lg"
|
||||
modal-class="b-modal">
|
||||
modal-class="b-modal"
|
||||
>
|
||||
<template #modal-header="{ close }">
|
||||
<div
|
||||
id="spell_show_edit_modal"
|
||||
class="h1 modal-title font-display font-weight-bold"
|
||||
>
|
||||
<div class="line-height-100">
|
||||
<span v-if="!spell.name">Nouveau sort</span>
|
||||
<span v-if="spell.name">{{ spell.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="close()"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-slot:modal-header="{ close }">
|
||||
<div class="h1 modal-title font-display font-weight-bold" id="spell_show_edit_modal">
|
||||
<div class="line-height-100">
|
||||
<span v-if="!spell.name">Nouveau sort</span>
|
||||
<span v-if="spell.name">{{spell.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</template>
|
||||
<template #default>
|
||||
<form
|
||||
id="add-spell"
|
||||
@submit="addSpell"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_name"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Nom :</label>
|
||||
<input
|
||||
id="spell_name"
|
||||
v-model="spell.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="spell_name"
|
||||
placeholder="(256 caractères max.)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_description"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Description :</label>
|
||||
<textarea
|
||||
id="spell_description"
|
||||
v-model="spell.description"
|
||||
class="form-control"
|
||||
name="spell_description"
|
||||
placeholder="(2048 caractères max.)"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="spell_ritual"
|
||||
v-model="spell.is_ritual"
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
name="spell_ritual"
|
||||
>
|
||||
<label
|
||||
for="spell_ritual"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Rituel ? </label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_level"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Niveau :</label>
|
||||
<input
|
||||
id="spell_level"
|
||||
v-model="spell.level"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="spell_level"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
placeholder="(Nombre entier de 0 à 100)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_schools"
|
||||
class="font-weight-bold col-form-label"
|
||||
>École(s) :</label>
|
||||
<select
|
||||
id="spell_schools"
|
||||
v-model="spell.schools"
|
||||
class="form-control"
|
||||
name="spell_schools"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(school, index) in all_schools"
|
||||
:key="index"
|
||||
:value="'school_' + school.id"
|
||||
>
|
||||
{{ school.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_charge"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Charge :</label>
|
||||
<input
|
||||
id="spell_charge"
|
||||
v-model="spell.charge"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="spell_charge"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
placeholder="(Nombre entier de 0 à 100)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_ingredients"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Ingrédient(s) :</label>
|
||||
<select
|
||||
id="spell_ingredients"
|
||||
v-model="spell.ingredients"
|
||||
class="form-control"
|
||||
name="spell_ingredients"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(ingredient,index) in all_ingredients"
|
||||
:key="index"
|
||||
:value="'ingredient_' + ingredient.id"
|
||||
>
|
||||
{{ ingredient.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_cost"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Coût :</label>
|
||||
<input
|
||||
id="spell_cost"
|
||||
v-model="spell.cost"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="spell_cost"
|
||||
placeholder="(32 caractères max.)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_variables"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Variable(s) :</label>
|
||||
<select
|
||||
id="spell_variables"
|
||||
v-model="spell.variables"
|
||||
class="form-control"
|
||||
name="spell_variables"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(variable,index) in all_variables"
|
||||
:key="index"
|
||||
:value="'variable_' + variable.id"
|
||||
>
|
||||
{{ variable.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template v-slot:default>
|
||||
<form id="add-spell" @submit="addSpell">
|
||||
<div class="form-group">
|
||||
<label for="spell_name" class="font-weight-bold col-form-label">Nom :</label>
|
||||
<input type="text" class="form-control" name="spell_name" id="spell_name" placeholder="(256 caractères max.)" v-model="spell.name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_description" class="font-weight-bold col-form-label">Description :</label>
|
||||
<textarea class="form-control" name="spell_description" id="spell_description" placeholder="(2048 caractères max.)" v-model="spell.description"></textarea>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input type="checkbox" class="form-check-input" id="spell_ritual" name="spell_ritual" v-model="spell.is_ritual">
|
||||
<label for="spell_ritual" class="font-weight-bold col-form-label">Rituel ? </label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_level" class="font-weight-bold col-form-label">Niveau :</label>
|
||||
<input type="number" class="form-control" name="spell_level" id="spell_level" min="0" max="100" step="1" placeholder="(Nombre entier de 0 à 100)" v-model="spell.level">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_schools" class="font-weight-bold col-form-label">École(s) :</label>
|
||||
<select class="form-control" id="spell_schools" name="spell_schools" multiple v-model="spell.schools">
|
||||
<option v-for="(school, index) in all_schools" :key="index" :value="'school_' + school.id">{{school.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_charge" class="font-weight-bold col-form-label">Charge :</label>
|
||||
<input type="number" class="form-control" name="spell_charge" id="spell_charge" min="0" max="100" step="1" placeholder="(Nombre entier de 0 à 100)" v-model="spell.charge">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_ingredients" class="font-weight-bold col-form-label">Ingrédient(s) :</label>
|
||||
<select class="form-control" id="spell_ingredients" name="spell_ingredients" multiple v-model="spell.ingredients">
|
||||
<option v-for="(ingredient,index) in all_ingredients" :key="index" :value="'ingredient_' + ingredient.id">{{ingredient.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_cost" class="font-weight-bold col-form-label">Coût :</label>
|
||||
<input type="text" class="form-control" name="spell_cost" id="spell_cost" placeholder="(32 caractères max.)" v-model="spell.cost">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_variables" class="font-weight-bold col-form-label">Variable(s) :</label>
|
||||
<select class="form-control" id="spell_variables" name="spell_variables" multiple v-model="spell.variables">
|
||||
<option v-for="(variable,index) in all_variables" :key="index" :value="'variable_' + variable.id">{{variable.description}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template v-slot:modal-footer="{ close }">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal" @click="close()">Fermer</button>
|
||||
<input type="submit" class="btn btn-primary" value="Enregistrer" form="add-spell">
|
||||
</template>
|
||||
|
||||
</b-modal>
|
||||
<template #modal-footer="{ close }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-dismiss="modal"
|
||||
@click="close()"
|
||||
>
|
||||
Fermer
|
||||
</button>
|
||||
<input
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
value="Enregistrer"
|
||||
form="add-spell"
|
||||
>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
|
||||
const Spells = RepositoryFactory.get('spells')
|
||||
const Schools = RepositoryFactory.get('schools')
|
||||
const Variables = RepositoryFactory.get('variables')
|
||||
const Ingredients = RepositoryFactory.get('ingredients')
|
||||
const Spells = RepositoryFactory.get('spells');
|
||||
const Schools = RepositoryFactory.get('schools');
|
||||
const Variables = RepositoryFactory.get('variables');
|
||||
const Ingredients = RepositoryFactory.get('ingredients');
|
||||
|
||||
export default {
|
||||
'name': 'add-spell-card',
|
||||
data() {
|
||||
return {
|
||||
spell: {
|
||||
type: Object,
|
||||
name: "",
|
||||
description: "",
|
||||
is_ritual: false,
|
||||
level: 0,
|
||||
cost: "0",
|
||||
charge: 0,
|
||||
schools: [],
|
||||
variables: [],
|
||||
ingredients: [],
|
||||
},
|
||||
all_schools: [],
|
||||
all_variables: [],
|
||||
all_ingredients: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Gets all relevant info for multiple selects
|
||||
let fetchSchools = Schools.getAll()
|
||||
let fetchVariables = Variables.getAll()
|
||||
let fetchIngredients = Ingredients.getAll()
|
||||
'name': 'AddSpellCard',
|
||||
data() {
|
||||
return {
|
||||
spell: {
|
||||
type: Object,
|
||||
name: "",
|
||||
description: "",
|
||||
is_ritual: false,
|
||||
level: 0,
|
||||
cost: "0",
|
||||
charge: 0,
|
||||
schools: [],
|
||||
variables: [],
|
||||
ingredients: [],
|
||||
},
|
||||
all_schools: [],
|
||||
all_variables: [],
|
||||
all_ingredients: [],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// Gets all relevant info for multiple selects
|
||||
let fetchSchools = Schools.getAll();
|
||||
let fetchVariables = Variables.getAll();
|
||||
let fetchIngredients = Ingredients.getAll();
|
||||
|
||||
Promise.all([fetchSchools, fetchVariables, fetchIngredients])
|
||||
Promise.all([fetchSchools, fetchVariables, fetchIngredients])
|
||||
.then(v => {
|
||||
this.all_schools = v[0].data;
|
||||
this.all_variables = v[1].data;
|
||||
this.all_ingredients = v[2].data;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$refs["add_spell_modal"].show();
|
||||
this.$root.$on('bv::modal::hide', () => {
|
||||
this.$emit('cancelAdd');
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
addSpell(e) {
|
||||
e.preventDefault();
|
||||
|
||||
let schoolsData = Object.values(this.spell.schools).map(v => {
|
||||
return parseInt(v.slice(7));
|
||||
});
|
||||
let variablesData = Object.values(this.spell.variables).map(v => {
|
||||
return parseInt(v.slice(9));
|
||||
});
|
||||
let ingredientsData = Object.values(this.spell.ingredients).map(v => {
|
||||
return parseInt(v.slice(11));
|
||||
});
|
||||
|
||||
let data = {
|
||||
name: this.spell.name,
|
||||
description: this.spell.description,
|
||||
is_ritual: !!+this.spell.is_ritual,
|
||||
level: parseInt(this.spell.level),
|
||||
cost: this.spell.cost,
|
||||
charge: parseInt(this.spell.charge),
|
||||
schools: schoolsData,
|
||||
variables: variablesData,
|
||||
ingredients: ingredientsData,
|
||||
};
|
||||
|
||||
Spells.addOne(data)
|
||||
.then(v => {
|
||||
this.all_schools = v[0].data
|
||||
this.all_variables = v[1].data
|
||||
this.all_ingredients = v[2].data
|
||||
this.$emit('addSpell', v.data);
|
||||
this.$refs["add_spell_modal"].hide();
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
mounted() {
|
||||
this.$refs["add_spell_modal"].show()
|
||||
this.$root.$on('bv::modal::hide', () => {
|
||||
this.$emit('cancelAdd')
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
addSpell(e) {
|
||||
e.preventDefault()
|
||||
|
||||
let schoolsData = Object.values(this.spell.schools).map(v => { return parseInt(v.slice(7)) })
|
||||
let variablesData = Object.values(this.spell.variables).map(v => { return parseInt(v.slice(9)) })
|
||||
let ingredientsData = Object.values(this.spell.ingredients).map(v => { return parseInt(v.slice(11)) })
|
||||
|
||||
let data = {
|
||||
name: this.spell.name,
|
||||
description: this.spell.description,
|
||||
is_ritual: !!+this.spell.is_ritual,
|
||||
level: parseInt(this.spell.level),
|
||||
cost: this.spell.cost,
|
||||
charge: parseInt(this.spell.charge),
|
||||
schools: schoolsData,
|
||||
variables: variablesData,
|
||||
ingredients: ingredientsData,
|
||||
}
|
||||
|
||||
Spells.addOne(data)
|
||||
.then(v => {
|
||||
this.$emit('addSpell', v.data)
|
||||
this.$refs["add_spell_modal"].hide()
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,197 +1,341 @@
|
||||
<template>
|
||||
<b-modal
|
||||
<b-modal
|
||||
ref="edit_spell_modal"
|
||||
size="lg"
|
||||
modal-class="b-modal"
|
||||
:spell="computeSpell">
|
||||
:spell="computeSpell"
|
||||
>
|
||||
<template #modal-header="{ close }">
|
||||
<div
|
||||
id="spell_show_edit_modal"
|
||||
class="h1 modal-title font-display font-weight-bold"
|
||||
>
|
||||
<div class="line-height-100">
|
||||
{{ spell.name }}#{{ spell.id }}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="close()"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-slot:modal-header="{ close }">
|
||||
<div class="h1 modal-title font-display font-weight-bold" id="spell_show_edit_modal"><div class="line-height-100">{{spell.name}}#{{spell.id}}</div></div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @click="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-slot:default>
|
||||
<form id="update-spell" ref="update-spell" @submit="updateSpell">
|
||||
<div class="form-group">
|
||||
<label for="spell_name" class="font-weight-bold col-form-label">Nom :</label>
|
||||
<input type="text" class="form-control" name="spell_name" id="spell_name" placeholder="(256 caractères max.)" v-model="spell.name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_description" class="font-weight-bold col-form-label">Description :</label>
|
||||
<textarea class="form-control" name="spell_description" id="spell_description" placeholder="(2048 caractères max.)" v-model="spell.description"></textarea>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input type="checkbox" class="form-check-input" id="spell_ritual" name="spell_ritual" v-model="spell.is_ritual">
|
||||
<label for="spell_ritual" class="font-weight-bold col-form-label">Rituel ? </label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_level" class="font-weight-bold col-form-label">Niveau :</label>
|
||||
<input type="number" class="form-control" name="spell_level" id="spell_level" min="0" max="100" step="1" placeholder="(Nombre entier de 0 à 100)" v-model="spell.level">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_schools" class="font-weight-bold col-form-label">École(s) :</label>
|
||||
<select class="form-control" id="spell_schools" name="spell_schools" multiple v-model="spell.spell_school_ids_value">
|
||||
<option v-for="(school, index) in all_schools" :key="index" :value="'school_' + school.id">{{school.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_charge" class="font-weight-bold col-form-label">Charge :</label>
|
||||
<input type="number" class="form-control" name="spell_charge" id="spell_charge" min="0" max="100" step="1" placeholder="(Nombre entier de 0 à 100)" v-model="spell.charge">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_ingredients" class="font-weight-bold col-form-label">Ingrédient(s) :</label>
|
||||
<select class="form-control" id="spell_ingredients" name="spell_ingredients" multiple v-model="spell.spell_ingredient_ids_value">
|
||||
<option v-for="(ingredient,index) in all_ingredients" :key="index" :value="'ingredient_' + ingredient.id">{{ingredient.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_cost" class="font-weight-bold col-form-label">Coût :</label>
|
||||
<input type="text" class="form-control" name="spell_cost" id="spell_cost" placeholder="(32 caractères max.)" v-model="spell.cost">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="spell_variables" class="font-weight-bold col-form-label">Variable(s) :</label>
|
||||
<select class="form-control" id="spell_variables" name="spell_variables" multiple v-model="spell.spell_variable_ids_value">
|
||||
<option v-for="(variable,index) in all_variables" :key="index" :value="'variable_' + variable.id">{{variable.description}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
<template #default>
|
||||
<form
|
||||
id="update-spell"
|
||||
ref="update-spell"
|
||||
@submit="updateSpell"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_name"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Nom :</label>
|
||||
<input
|
||||
id="spell_name"
|
||||
v-model="spell.name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="spell_name"
|
||||
placeholder="(256 caractères max.)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_description"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Description :</label>
|
||||
<textarea
|
||||
id="spell_description"
|
||||
v-model="spell.description"
|
||||
class="form-control"
|
||||
name="spell_description"
|
||||
placeholder="(2048 caractères max.)"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="spell_ritual"
|
||||
v-model="spell.is_ritual"
|
||||
type="checkbox"
|
||||
class="form-check-input"
|
||||
name="spell_ritual"
|
||||
>
|
||||
<label
|
||||
for="spell_ritual"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Rituel ? </label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_level"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Niveau :</label>
|
||||
<input
|
||||
id="spell_level"
|
||||
v-model="spell.level"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="spell_level"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
placeholder="(Nombre entier de 0 à 100)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_schools"
|
||||
class="font-weight-bold col-form-label"
|
||||
>École(s) :</label>
|
||||
<select
|
||||
id="spell_schools"
|
||||
v-model="spell.spell_school_ids_value"
|
||||
class="form-control"
|
||||
name="spell_schools"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(school, index) in all_schools"
|
||||
:key="index"
|
||||
:value="'school_' + school.id"
|
||||
>
|
||||
{{ school.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_charge"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Charge :</label>
|
||||
<input
|
||||
id="spell_charge"
|
||||
v-model="spell.charge"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="spell_charge"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
placeholder="(Nombre entier de 0 à 100)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_ingredients"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Ingrédient(s) :</label>
|
||||
<select
|
||||
id="spell_ingredients"
|
||||
v-model="spell.spell_ingredient_ids_value"
|
||||
class="form-control"
|
||||
name="spell_ingredients"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(ingredient,index) in all_ingredients"
|
||||
:key="index"
|
||||
:value="'ingredient_' + ingredient.id"
|
||||
>
|
||||
{{ ingredient.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_cost"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Coût :</label>
|
||||
<input
|
||||
id="spell_cost"
|
||||
v-model="spell.cost"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="spell_cost"
|
||||
placeholder="(32 caractères max.)"
|
||||
>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="spell_variables"
|
||||
class="font-weight-bold col-form-label"
|
||||
>Variable(s) :</label>
|
||||
<select
|
||||
id="spell_variables"
|
||||
v-model="spell.spell_variable_ids_value"
|
||||
class="form-control"
|
||||
name="spell_variables"
|
||||
multiple
|
||||
>
|
||||
<option
|
||||
v-for="(variable,index) in all_variables"
|
||||
:key="index"
|
||||
:value="'variable_' + variable.id"
|
||||
>
|
||||
{{ variable.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template v-slot:modal-footer="{ close }">
|
||||
<button type="button" class="btn btn-danger" data-dismiss="modal" @click="close()">Fermer</button>
|
||||
<!-- <input type="button" class="btn btn-success" value="Enregistrer comme nouveau" @click="cloneSpell()"> -->
|
||||
<input type="submit" class="btn btn-primary" value="Enregistrer" form="update-spell">
|
||||
</template>
|
||||
</b-modal>
|
||||
<template #modal-footer="{ close }">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
data-dismiss="modal"
|
||||
@click="close()"
|
||||
>
|
||||
Fermer
|
||||
</button>
|
||||
<!-- <input type="button" class="btn btn-success" value="Enregistrer comme nouveau" @click="cloneSpell()"> -->
|
||||
<input
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
value="Enregistrer"
|
||||
form="update-spell"
|
||||
>
|
||||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Spells = RepositoryFactory.get('spells')
|
||||
const Schools = RepositoryFactory.get('schools')
|
||||
const Variables = RepositoryFactory.get('variables')
|
||||
const Ingredients = RepositoryFactory.get('ingredients')
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Spells = RepositoryFactory.get('spells');
|
||||
const Schools = RepositoryFactory.get('schools');
|
||||
const Variables = RepositoryFactory.get('variables');
|
||||
const Ingredients = RepositoryFactory.get('ingredients');
|
||||
|
||||
export default {
|
||||
name: 'edit-spell-card',
|
||||
props: {
|
||||
spell: {
|
||||
type: Object,
|
||||
required: true,
|
||||
id: Number,
|
||||
name: String,
|
||||
description: String,
|
||||
is_ritual: Boolean,
|
||||
schools: Array,
|
||||
variables: Array,
|
||||
ingredients: Array,
|
||||
},
|
||||
name: 'EditSpellCard',
|
||||
props: {
|
||||
spell: {
|
||||
type: Object,
|
||||
required: true,
|
||||
id: Number,
|
||||
name: String,
|
||||
description: String,
|
||||
is_ritual: Boolean,
|
||||
schools: Array,
|
||||
variables: Array,
|
||||
ingredients: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
all_schools: [],
|
||||
all_variables: [],
|
||||
all_ingredients: [],
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
all_schools: [],
|
||||
all_variables: [],
|
||||
all_ingredients: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
computeSpell() {
|
||||
let output = this.spell;
|
||||
output.spell_school_ids = [];
|
||||
output.spell_variable_ids = [];
|
||||
output.spell_ingredient_ids = [];
|
||||
output.spell_school_ids_value = [];
|
||||
output.spell_variable_ids_value = [];
|
||||
output.spell_ingredient_ids_value = [];
|
||||
|
||||
output.schools.forEach(element => {
|
||||
output.spell_school_ids.push(element['id']);
|
||||
});
|
||||
output.variables.forEach(element => {
|
||||
output.spell_variable_ids.push(element['id']);
|
||||
});
|
||||
output.ingredients.forEach(element => {
|
||||
output.spell_ingredient_ids.push(element['id']);
|
||||
});
|
||||
|
||||
output.spell_school_ids.forEach(element => {
|
||||
output.spell_school_ids_value.push("school_" + element);
|
||||
});
|
||||
output.spell_variable_ids.forEach(element => {
|
||||
output.spell_variable_ids_value.push("variable_" + element);
|
||||
});
|
||||
output.spell_ingredient_ids.forEach(element => {
|
||||
output.spell_ingredient_ids_value.push("ingredient_" + element);
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
computeSpell: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$refs["edit_spell_modal"].show();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Gets all relevant info for multiple selects
|
||||
let fetchSchools = Schools.getAll();
|
||||
let fetchVariables = Variables.getAll();
|
||||
let fetchIngredients = Ingredients.getAll();
|
||||
|
||||
Promise.all([fetchSchools, fetchVariables, fetchIngredients])
|
||||
.then(v => {
|
||||
this.all_schools = v[0].data;
|
||||
this.all_variables = v[1].data;
|
||||
this.all_ingredients = v[2].data;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$refs["edit_spell_modal"].show();
|
||||
this.$root.$on('bv::modal::hide', () => {
|
||||
this.$emit('editSpell', {});
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
cloneSpell() {
|
||||
},
|
||||
computed: {
|
||||
computeSpell() {
|
||||
let output = this.spell
|
||||
output.spell_school_ids = []
|
||||
output.spell_variable_ids = []
|
||||
output.spell_ingredient_ids = []
|
||||
output.spell_school_ids_value = []
|
||||
output.spell_variable_ids_value = []
|
||||
output.spell_ingredient_ids_value = []
|
||||
updateSpell(e) {
|
||||
e.preventDefault();
|
||||
|
||||
output.schools.forEach(element => {
|
||||
output.spell_school_ids.push(element['id'])
|
||||
})
|
||||
output.variables.forEach(element => {
|
||||
output.spell_variable_ids.push(element['id'])
|
||||
})
|
||||
output.ingredients.forEach(element => {
|
||||
output.spell_ingredient_ids.push(element['id'])
|
||||
})
|
||||
let schoolsData = Object.values(this.spell.spell_school_ids_value).map(v => {
|
||||
return parseInt(v.slice(7));
|
||||
});
|
||||
let variablesData = Object.values(this.spell.spell_variable_ids_value).map(v => {
|
||||
return parseInt(v.slice(9));
|
||||
});
|
||||
let ingredientsData = Object.values(this.spell.spell_ingredient_ids_value).map(v => {
|
||||
return parseInt(v.slice(11));
|
||||
});
|
||||
|
||||
output.spell_school_ids.forEach(element => {
|
||||
output.spell_school_ids_value.push("school_" + element)
|
||||
})
|
||||
output.spell_variable_ids.forEach(element => {
|
||||
output.spell_variable_ids_value.push("variable_" + element)
|
||||
})
|
||||
output.spell_ingredient_ids.forEach(element => {
|
||||
output.spell_ingredient_ids_value.push("ingredient_" + element)
|
||||
})
|
||||
let data = {
|
||||
name: this.spell.name,
|
||||
description: this.spell.description,
|
||||
is_ritual: !!+this.spell.is_ritual,
|
||||
level: parseInt(this.spell.level),
|
||||
cost: this.spell.cost,
|
||||
charge: parseInt(this.spell.charge),
|
||||
schools: schoolsData,
|
||||
variables: variablesData,
|
||||
ingredients: ingredientsData,
|
||||
};
|
||||
|
||||
return output
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Gets all relevant info for multiple selects
|
||||
let fetchSchools = Schools.getAll()
|
||||
let fetchVariables = Variables.getAll()
|
||||
let fetchIngredients = Ingredients.getAll()
|
||||
|
||||
Promise.all([fetchSchools, fetchVariables, fetchIngredients])
|
||||
Spells.updateOne(this.spell.id, data)
|
||||
.then(v => {
|
||||
this.all_schools = v[0].data
|
||||
this.all_variables = v[1].data
|
||||
this.all_ingredients = v[2].data
|
||||
this.$emit('updateSpell', v.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
this.$refs["edit_spell_modal"].show()
|
||||
this.$root.$on('bv::modal::hide', () => {
|
||||
this.$emit('editSpell', {})
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
computeSpell: {
|
||||
deep: true,
|
||||
handler() {
|
||||
this.$refs["edit_spell_modal"].show()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cloneSpell() {
|
||||
},
|
||||
updateSpell(e) {
|
||||
e.preventDefault()
|
||||
|
||||
let schoolsData = Object.values(this.spell.spell_school_ids_value).map(v => { return parseInt(v.slice(7)) })
|
||||
let variablesData = Object.values(this.spell.spell_variable_ids_value).map(v => { return parseInt(v.slice(9)) })
|
||||
let ingredientsData = Object.values(this.spell.spell_ingredient_ids_value).map(v => { return parseInt(v.slice(11)) })
|
||||
|
||||
let data = {
|
||||
name: this.spell.name,
|
||||
description: this.spell.description,
|
||||
is_ritual: !!+this.spell.is_ritual,
|
||||
level: parseInt(this.spell.level),
|
||||
cost: this.spell.cost,
|
||||
charge: parseInt(this.spell.charge),
|
||||
schools: schoolsData,
|
||||
variables: variablesData,
|
||||
ingredients: ingredientsData,
|
||||
}
|
||||
|
||||
Spells.updateOne(this.spell.id, data)
|
||||
.then(v => {
|
||||
this.$emit('updateSpell', v.data)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,150 +1,204 @@
|
||||
<template>
|
||||
<div
|
||||
:class="main_school"
|
||||
class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4 grid-item grid-sizer"
|
||||
>
|
||||
<div
|
||||
:class="main_school"
|
||||
class="col-12 col-sm-6 col-lg-4 col-xl-3 mb-4 grid-item grid-sizer">
|
||||
<div class="spellcard bg-white p-4 rounded text-dark shadow" style="border-left-width:4px;border-left-style:solid;">
|
||||
class="spellcard bg-white p-4 rounded text-dark shadow"
|
||||
style="border-left-width:4px;border-left-style:solid;"
|
||||
>
|
||||
<div
|
||||
:title="spell.name"
|
||||
class="h3 font-display font-weight-bold text-wrap word-break"
|
||||
style="line-height:100%;"
|
||||
>
|
||||
<router-link
|
||||
:to="`/sorts/${spell.id}`"
|
||||
class="text-decoration-none"
|
||||
>
|
||||
{{ spell.name }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div :title="spell.name" class="h3 font-display font-weight-bold text-wrap word-break" style="line-height:100%;">
|
||||
<router-link :to="`/sorts/${spell.id}`" class="text-decoration-none">{{spell.name}}</router-link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="font-weight-700 text-muted d-inline-block">Niveau {{spell.level}}</div>
|
||||
<span> · </span>
|
||||
<div class="text-muted d-inline-block">
|
||||
<span v-for="(school,index) in spell.schools" :key="index">
|
||||
<span v-if="index!=0">, </span>
|
||||
<router-link :to="`ecoles/${school.id}`" class="text-secondary">{{school.name}}</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="spell.charge!=0" class="small font-weight-bold">
|
||||
<span>Charge {{spell.charge}} tour(s)</span>
|
||||
</div>
|
||||
|
||||
<div v-if="spell.is_ritual" class="small font-weight-bold">
|
||||
<span>Rituel</span>
|
||||
</div>
|
||||
|
||||
<div v-if="spell.ingredients.length>0" class="small">
|
||||
<span class="font-weight-bold">Nécessite </span>
|
||||
<span v-for="(ingredient,index) in spell.ingredients" :key="index">
|
||||
<span v-if="index!=0">, </span>
|
||||
<span>{{ingredient.name}}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-clipboard="spell.description"
|
||||
:id="'spell_description_' + spell.id"
|
||||
v-b-tooltip.click
|
||||
placement="bottom"
|
||||
title="Description copiée !"
|
||||
class="small text-muted mt-2">
|
||||
<span style="white-space: pre-wrap;">{{spell.description}}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<div class="font-weight-bold d-inline-block"><span>Coût </span>{{spell.cost}}</div>
|
||||
<div v-if="spell.variables.length>0" class="small d-inline-block">, où :</div>
|
||||
<div class=small>
|
||||
<span v-for="(variable,index) in spell.variables" :key="index">
|
||||
<span class="font-weight-bold">
|
||||
<span v-if="index!=0"><br></span>
|
||||
<span>{{String.fromCharCode(120+index)}}</span>
|
||||
</span>
|
||||
<span> = {{variable.description}}</span>
|
||||
</span>
|
||||
</div>
|
||||
<footer v-if="user" class="text-right">
|
||||
<a class="h5 text-secondary mr-1">
|
||||
<i class="mad" @click="editSpell(spell)">edit</i>
|
||||
</a>
|
||||
<a class="h5 text-danger">
|
||||
<i class="mad" @click="deleteSpell(spell)">delete</i>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-weight-700 text-muted d-inline-block">
|
||||
Niveau {{ spell.level }}
|
||||
</div>
|
||||
<span> · </span>
|
||||
<div class="text-muted d-inline-block">
|
||||
<span
|
||||
v-for="(school,index) in spell.schools"
|
||||
:key="index"
|
||||
>
|
||||
<span v-if="index!=0">, </span>
|
||||
<router-link
|
||||
:to="`ecoles/${school.id}`"
|
||||
class="text-secondary"
|
||||
>{{ school.name }}</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="spell.charge!=0"
|
||||
class="small font-weight-bold"
|
||||
>
|
||||
<span>Charge {{ spell.charge }} tour(s)</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="spell.is_ritual"
|
||||
class="small font-weight-bold"
|
||||
>
|
||||
<span>Rituel</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="spell.ingredients.length>0"
|
||||
class="small"
|
||||
>
|
||||
<span class="font-weight-bold">Nécessite </span>
|
||||
<span
|
||||
v-for="(ingredient,index) in spell.ingredients"
|
||||
:key="index"
|
||||
>
|
||||
<span v-if="index!=0">, </span>
|
||||
<span>{{ ingredient.name }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:id="'spell_description_' + spell.id"
|
||||
v-clipboard="spell.description"
|
||||
v-b-tooltip.click
|
||||
placement="bottom"
|
||||
title="Description copiée !"
|
||||
class="small text-muted mt-2"
|
||||
>
|
||||
<span class="prewrap">{{ spell.description }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<div class="font-weight-bold d-inline-block">
|
||||
<span>Coût : </span>{{ spell.cost }}
|
||||
</div>
|
||||
<div
|
||||
v-if="spell.variables.length>0"
|
||||
class="small d-inline-block"
|
||||
>
|
||||
, où :
|
||||
</div>
|
||||
<div class="small">
|
||||
<span
|
||||
v-for="(variable,index) in spell.variables"
|
||||
:key="index"
|
||||
>
|
||||
<span class="font-weight-bold">
|
||||
<span v-if="index!=0"><br></span>
|
||||
<span>{{ String.fromCharCode(120+index) }}</span>
|
||||
</span>
|
||||
<span> = {{ variable.description }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<footer
|
||||
v-if="user"
|
||||
class="text-right"
|
||||
>
|
||||
<a class="h5 text-secondary mr-1">
|
||||
<i
|
||||
class="mad"
|
||||
@click="editSpell(spell)"
|
||||
>edit</i>
|
||||
</a>
|
||||
<a class="h5 text-danger">
|
||||
<i
|
||||
class="mad"
|
||||
@click="deleteSpell(spell)"
|
||||
>delete</i>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Spells = RepositoryFactory.get('spells')
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Spells = RepositoryFactory.get('spells');
|
||||
|
||||
export default {
|
||||
name: 'spell-card',
|
||||
props: {
|
||||
spell: Object,
|
||||
name: 'SpellCard',
|
||||
props: {
|
||||
spell: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
main_school: this.spell.schools[0].name,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.getUserProfile;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.main_school = this.main_school.toLowerCase();
|
||||
},
|
||||
methods: {
|
||||
editSpell(spell) {
|
||||
this.$emit('editSpell', spell);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
main_school: this.spell.schools[0].name,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.main_school = this.main_school.toLowerCase()
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.state.user
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editSpell(spell) {
|
||||
this.$emit('editSpell', spell)
|
||||
},
|
||||
deleteSpell(spell) {
|
||||
Spells.deleteOne(this.spell.id)
|
||||
.then(() => {
|
||||
this.$emit('deleteSpell', spell)
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
deleteSpell(spell) {
|
||||
Spells.deleteOne(this.spell.id)
|
||||
.then(() => {
|
||||
this.$emit('deleteSpell', spell);
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.spell-card {
|
||||
footer {
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.spell-card {
|
||||
footer {
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
@mixin colorschool($sname,$scolor) {
|
||||
&.#{$sname} {
|
||||
.spellcard { border-left-color: $scolor; }
|
||||
.h3>a { color: $scolor; }
|
||||
}
|
||||
}
|
||||
@include colorschool(lumomancie,#babaa4);
|
||||
@include colorschool(vitamancie,#57ab6e);
|
||||
@include colorschool(obstrumancie,#bd4a66);
|
||||
@include colorschool(tenebromancie,#404842);
|
||||
@include colorschool(necromancie,#5d4777);
|
||||
@include colorschool(morbomancie,#d8733d);
|
||||
@include colorschool(pyromancie,#b6362a);
|
||||
@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);
|
||||
@include colorschool(cruciomancie,#252451);
|
||||
@include colorschool(chronomancie,#79896a);
|
||||
@include colorschool(spatiomancie,#2d4776);
|
||||
@include colorschool(kénomancie,#101010);
|
||||
@include colorschool(lutomancie,#4e2827);
|
||||
@include colorschool(échomancie,#6d9fd1);
|
||||
@include colorschool(protomancie,#4f5751);
|
||||
@include colorschool(rebumancie,#8e7245);
|
||||
@include colorschool(vocamancie,#247864);
|
||||
@include colorschool(somamancie,#976c67);
|
||||
@include colorschool(antimancie,#ad95c1);
|
||||
}
|
||||
@mixin colorschool($sname,$scolor) {
|
||||
&.#{$sname} {
|
||||
.spellcard { border-left-color: $scolor; }
|
||||
.h3>a { color: $scolor; }
|
||||
}
|
||||
}
|
||||
@include colorschool(lumomancie,#babaa4);
|
||||
@include colorschool(vitamancie,#57ab6e);
|
||||
@include colorschool(obstrumancie,#bd4a66);
|
||||
@include colorschool(tenebromancie,#404842);
|
||||
@include colorschool(necromancie,#5d4777);
|
||||
@include colorschool(morbomancie,#d8733d);
|
||||
@include colorschool(pyromancie,#b6362a);
|
||||
@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);
|
||||
@include colorschool(cruciomancie,#252451);
|
||||
@include colorschool(chronomancie,#79896a);
|
||||
@include colorschool(spatiomancie,#2d4776);
|
||||
@include colorschool(kénomancie,#101010);
|
||||
@include colorschool(lutomancie,#4e2827);
|
||||
@include colorschool(échomancie,#6d9fd1);
|
||||
@include colorschool(protomancie,#4f5751);
|
||||
@include colorschool(rebumancie,#8e7245);
|
||||
@include colorschool(vocamancie,#247864);
|
||||
@include colorschool(somamancie,#976c67);
|
||||
@include colorschool(antimancie,#ad95c1);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,224 +1,290 @@
|
||||
<template>
|
||||
<div class="spell-list-wrapper">
|
||||
|
||||
<div class="mb-4">
|
||||
<form>
|
||||
<div class="form-group mb-2">
|
||||
<input type="text" class="form-control" v-model="search_text" name="search_terms" id="search_terms" placeholder="Rechercher l'arcane">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="search_term" id="search_fields_name" value="search_fields_name">
|
||||
<label class="form-check-label" for="search_fields_name">Nom</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="search_term" id="search_fields_description" value="search_fields_description" checked>
|
||||
<label class="form-check-label" for="search_fields_description">Description</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="search_term" id="search_fields_schools" value="search_fields_schools" disabled>
|
||||
<label class="form-check-label" for="search_fields_schools">École(s)</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="search_term" id="search_fields_ingredients" value="search_fields_ingredients" disabled>
|
||||
<label class="form-check-label" for="search_fields_ingredients">Ingrédients</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="search_term" id="search_fields_variables" value="search_fields_variables" disabled>
|
||||
<label class="form-check-label" for="search_fields_variables">Variables</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="spell-list-wrapper">
|
||||
<div class="mb-4">
|
||||
<form>
|
||||
<div class="form-group mb-2">
|
||||
<input
|
||||
id="search_terms"
|
||||
v-model="search_text"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="search_terms"
|
||||
placeholder="Rechercher l'arcane"
|
||||
>
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-if="user"
|
||||
@click="showAdd"
|
||||
type="button"
|
||||
class="btn font-display font-weight-bold btn-lg btn-outline-dark btn-block shadow-sm mb-4">
|
||||
|
||||
<i class="mad">add</i>
|
||||
<span>Ajouter un sort</span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
v-if="filteredSpells.length > 0"
|
||||
class="spell-list-wrapper">
|
||||
<div
|
||||
class="row spells-list"
|
||||
v-masonry
|
||||
transition-duration="1s"
|
||||
item-selector=".spell-card">
|
||||
<spell-card
|
||||
class="spell-card"
|
||||
v-masonry-tile
|
||||
v-for="(spell) in filteredSpells"
|
||||
:key="spell.id"
|
||||
:spell="spell"
|
||||
@editSpell="editSpell"
|
||||
@deleteSpell="deleteSpell" />
|
||||
</div>
|
||||
|
||||
<edit-spell-card
|
||||
v-if="Object.keys(current_edit_spell).length > 0"
|
||||
:spell="current_edit_spell"
|
||||
@editSpell="editSpell"
|
||||
@updateSpell="updateSpell"/>
|
||||
|
||||
<add-spell-card
|
||||
v-if="adding_spell"
|
||||
@cancelAdd="cancelAdd"
|
||||
@addSpell="addSpell"/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="loader-wrapper">
|
||||
<loader/>
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="search_fields_name"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="search_term"
|
||||
value="search_fields_name"
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="search_fields_name"
|
||||
>Nom</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="search_fields_description"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="search_term"
|
||||
value="search_fields_description"
|
||||
checked
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="search_fields_description"
|
||||
>Description</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="search_fields_schools"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="search_term"
|
||||
value="search_fields_schools"
|
||||
disabled
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="search_fields_schools"
|
||||
>
|
||||
École(s)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="search_fields_ingredients"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="search_term"
|
||||
value="search_fields_ingredients"
|
||||
disabled
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="search_fields_ingredients"
|
||||
>Ingrédients</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
id="search_fields_variables"
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="search_term"
|
||||
value="search_fields_variables"
|
||||
disabled
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="search_fields_variables"
|
||||
>Variables</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-if="user"
|
||||
type="button"
|
||||
class="btn font-display font-weight-bold btn-lg btn-outline-dark btn-block shadow-sm mb-4"
|
||||
@click="showAdd"
|
||||
>
|
||||
<i class="mad">add</i>
|
||||
<span>Ajouter un sort</span>
|
||||
</button>
|
||||
|
||||
<div
|
||||
v-if="filteredSpells.length > 0"
|
||||
class="spell-list-wrapper"
|
||||
>
|
||||
<div
|
||||
v-masonry
|
||||
class="row spells-list"
|
||||
transition-duration="1s"
|
||||
item-selector=".spell-card"
|
||||
>
|
||||
<spell-card
|
||||
v-for="(spell) in filteredSpells"
|
||||
:key="spell.id"
|
||||
v-masonry-tile
|
||||
class="spell-card"
|
||||
:spell="spell"
|
||||
@editSpell="editSpell"
|
||||
@deleteSpell="deleteSpell"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<edit-spell-card
|
||||
v-if="Object.keys(current_edit_spell).length > 0"
|
||||
:spell="current_edit_spell"
|
||||
@editSpell="editSpell"
|
||||
@updateSpell="updateSpell"
|
||||
/>
|
||||
|
||||
<add-spell-card
|
||||
v-if="adding_spell"
|
||||
@cancelAdd="cancelAdd"
|
||||
@addSpell="addSpell"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="loader-wrapper"
|
||||
>
|
||||
<loader />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Components
|
||||
import SpellCard from "./spell-card"
|
||||
import EditSpellCard from "./edit-spell-card"
|
||||
import AddSpellCard from "./add-spell-card"
|
||||
import SpellCard from "./spell-card";
|
||||
import EditSpellCard from "./edit-spell-card";
|
||||
import AddSpellCard from "./add-spell-card";
|
||||
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Spells = RepositoryFactory.get('spells')
|
||||
const Schools = RepositoryFactory.get('schools')
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Spells = RepositoryFactory.get('spells');
|
||||
const Schools = RepositoryFactory.get('schools');
|
||||
|
||||
export default {
|
||||
name: 'spellslist',
|
||||
components: {
|
||||
'spell-card': SpellCard,
|
||||
'edit-spell-card': EditSpellCard,
|
||||
'add-spell-card': AddSpellCard,
|
||||
name: 'Spellslist',
|
||||
components: {
|
||||
'spell-card': SpellCard,
|
||||
'edit-spell-card': EditSpellCard,
|
||||
'add-spell-card': AddSpellCard,
|
||||
},
|
||||
props: {
|
||||
schoolId: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
props: {
|
||||
school_id: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
spells: [],
|
||||
loading: false,
|
||||
current_edit_spell: {},
|
||||
currentIndex: 1,
|
||||
adding_spell: false,
|
||||
search_text: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
filteredSpells() {
|
||||
return this.spells;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
spells: [],
|
||||
loading: false,
|
||||
current_edit_spell: {},
|
||||
currentIndex: 1,
|
||||
adding_spell: false,
|
||||
search_text: "",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredSpells() {
|
||||
return this.spells
|
||||
},
|
||||
user() {
|
||||
return this.$store.state.user
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.spells = this.filteredSpells
|
||||
if (!this.school_id) {
|
||||
this.getInitialSpells()
|
||||
} else {
|
||||
this.getInitialSchoolSpells()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.school_id) {
|
||||
this.scroll()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInitialSpells() {
|
||||
Spells.getPage(this.currentIndex)
|
||||
.then(v => {
|
||||
this.loading = true
|
||||
let spells = this.filteredSpells
|
||||
spells.push(v.data)
|
||||
this.spells = spells[0]
|
||||
})
|
||||
.then(() => {
|
||||
this.currentIndex++
|
||||
this.loading = false
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
getInitialSchoolSpells() {
|
||||
Schools.getSpellsFromOne(this.school_id)
|
||||
.then(v => {
|
||||
this.loading = true
|
||||
let spells = this.filteredSpells
|
||||
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) {
|
||||
Spells.getPage(this.currentIndex)
|
||||
.then(v => {
|
||||
this.loading = true
|
||||
let spells = this.filteredSpells
|
||||
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;
|
||||
},
|
||||
showAdd() {
|
||||
this.adding_spell = true
|
||||
},
|
||||
cancelAdd() {
|
||||
this.adding_spell = false
|
||||
},
|
||||
// Receives events to update the data
|
||||
addSpell(e) {
|
||||
Spells.getOne(e.id)
|
||||
.then(v => {
|
||||
let spells = this.filteredSpells
|
||||
spells.unshift(v.data)
|
||||
})
|
||||
.then(() => {
|
||||
this.adding_spell = false
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
updateSpell(e) {
|
||||
let oldSpell = this.spells.find(x => x.id === e.id)
|
||||
this.spells.splice(this.spells.indexOf(oldSpell), 1, e)
|
||||
this.current_edit_spell = {}
|
||||
},
|
||||
deleteSpell(e) {
|
||||
this.spells.splice(this.spells.indexOf(e), 1)
|
||||
this.current_edit_spell = {}
|
||||
}
|
||||
user() {
|
||||
return this.$store.state.user;
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.spells = this.filteredSpells;
|
||||
if (!this.school_id) {
|
||||
this.getInitialSpells();
|
||||
} else {
|
||||
this.getInitialSchoolSpells();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.school_id) {
|
||||
this.scroll();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInitialSpells() {
|
||||
Spells.getPage(this.currentIndex)
|
||||
.then(v => {
|
||||
this.loading = true;
|
||||
let spells = this.filteredSpells;
|
||||
spells.push(v.data);
|
||||
this.spells = spells[0];
|
||||
})
|
||||
.then(() => {
|
||||
this.currentIndex++;
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
getInitialSchoolSpells() {
|
||||
Schools.getSpellsFromOne(this.school_id)
|
||||
.then(v => {
|
||||
this.loading = true;
|
||||
let spells = this.filteredSpells;
|
||||
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) {
|
||||
Spells.getPage(this.currentIndex)
|
||||
.then(v => {
|
||||
this.loading = true;
|
||||
let spells = this.filteredSpells;
|
||||
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;
|
||||
},
|
||||
showAdd() {
|
||||
this.adding_spell = true;
|
||||
},
|
||||
cancelAdd() {
|
||||
this.adding_spell = false;
|
||||
},
|
||||
// Receives events to update the data
|
||||
addSpell(e) {
|
||||
Spells.getOne(e.id)
|
||||
.then(v => {
|
||||
let spells = this.filteredSpells;
|
||||
spells.unshift(v.data);
|
||||
})
|
||||
.then(() => {
|
||||
this.adding_spell = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
updateSpell(e) {
|
||||
let oldSpell = this.spells.find(x => x.id === e.id);
|
||||
this.spells.splice(this.spells.indexOf(oldSpell), 1, e);
|
||||
this.current_edit_spell = {};
|
||||
},
|
||||
deleteSpell(e) {
|
||||
this.spells.splice(this.spells.indexOf(e), 1);
|
||||
this.current_edit_spell = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
318
client/src/components/timeline/timeline.vue
Normal file
318
client/src/components/timeline/timeline.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<ul class="timeline">
|
||||
<li class="timeline-item period first">
|
||||
<div class="timeline-info" />
|
||||
<div class="timeline-content">
|
||||
<h2 class="timeline-title">
|
||||
LE RENOUVEAU
|
||||
</h2>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-info">
|
||||
<span>March 12, 2016</span>
|
||||
</div>
|
||||
<div class="timeline-marker" />
|
||||
<div class="timeline-content">
|
||||
<h3 class="timeline-title">
|
||||
Event Title
|
||||
</h3>
|
||||
<p>Nullam vel sem. Nullam vel sem. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Donec vitae sapien ut libero venenatis faucibus. ullam dictum felis eu pede mollis pretium. Pellentesque ut neque.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-info">
|
||||
<span>March 23, 2016</span>
|
||||
</div>
|
||||
<div class="timeline-marker" />
|
||||
<div class="timeline-content">
|
||||
<h3 class="timeline-title">
|
||||
Event Title
|
||||
</h3>
|
||||
<p>Nullam vel sem. Nullam vel sem. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Donec vitae sapien ut libero venenatis faucibus. ullam dictum felis eu pede mollis pretium. Pellentesque ut neque. </p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item period">
|
||||
<div class="timeline-info" />
|
||||
<div class="timeline-marker" />
|
||||
<div class="timeline-content">
|
||||
<h2 class="timeline-title">
|
||||
April 2016
|
||||
</h2>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-info">
|
||||
<span>April 02, 2016</span>
|
||||
</div>
|
||||
<div class="timeline-marker" />
|
||||
<div class="timeline-content">
|
||||
<h3 class="timeline-title">
|
||||
Event Title
|
||||
</h3>
|
||||
<p>Nullam vel sem. Nullam vel sem. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Donec vitae sapien ut libero venenatis faucibus. ullam dictum felis eu pede mollis pretium. Pellentesque ut neque. </p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item">
|
||||
<div class="timeline-info">
|
||||
<span>April 28, 2016</span>
|
||||
</div>
|
||||
<div class="timeline-marker" />
|
||||
<div class="timeline-content">
|
||||
<h3 class="timeline-title">
|
||||
Event Title
|
||||
</h3>
|
||||
<p>Nullam vel sem. Nullam vel sem. Integer ante arcu, accumsan a, consectetuer eget, posuere ut, mauris. Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Donec vitae sapien ut libero venenatis faucibus. ullam dictum felis eu pede mollis pretium. Pellentesque ut neque. </p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Timeline',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/*==================================
|
||||
TIMELINE
|
||||
==================================*/
|
||||
|
||||
/*-- GENERAL STYLES
|
||||
------------------------------*/
|
||||
.timeline {
|
||||
margin: 0;
|
||||
padding-top: 25px;
|
||||
width: 100%;
|
||||
line-height: 1.4em;
|
||||
list-style: none;
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
line-height: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
/*----- TIMELINE ITEM -----*/
|
||||
|
||||
.timeline-item {
|
||||
padding-left: 40px;
|
||||
position: relative;
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*----- TIMELINE INFO -----*/
|
||||
|
||||
.timeline-info {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3px;
|
||||
margin: 0 0 .5em 0;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/*----- TIMELINE MARKER -----*/
|
||||
|
||||
.timeline-marker {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0; left: 0;
|
||||
width: 15px;
|
||||
&:before {
|
||||
background: $primary-blue;
|
||||
border: 3px solid transparent;
|
||||
border-radius: 100%;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
top: 4px; left: 0;
|
||||
width: 15px;
|
||||
transition: background 0.3s ease-in-out, border 0.3s ease-in-out;
|
||||
}
|
||||
&:after {
|
||||
content: "";
|
||||
width: 3px;
|
||||
background: #CCD5DB;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 24px; bottom: 0; left: 6px;
|
||||
}
|
||||
.timeline-item:last-child &:after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
.timeline-item:not(.period):hover .timeline-marker:before {
|
||||
background: transparent;
|
||||
border: 3px solid $primary-blue;
|
||||
}
|
||||
|
||||
/*----- TIMELINE CONTENT -----*/
|
||||
|
||||
.timeline-content {
|
||||
padding-bottom: 40px;
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*----- TIMELINE PERIOD -----*/
|
||||
|
||||
.period {
|
||||
padding: 0;
|
||||
.timeline-info {
|
||||
display: none;
|
||||
}
|
||||
.timeline-marker {
|
||||
&:before {
|
||||
background: transparent;
|
||||
content: "";
|
||||
width: 15px;
|
||||
height: auto;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
top: 0;
|
||||
bottom: 30px;
|
||||
position: absolute;
|
||||
border-top: 3px solid #CCD5DB;
|
||||
border-bottom: 3px solid #CCD5DB;
|
||||
}
|
||||
&:after {
|
||||
content: "";
|
||||
height: 32px;
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
&:not(.first) {
|
||||
.timeline-content {
|
||||
padding: 40px 0 70px;
|
||||
}
|
||||
}
|
||||
.timeline-title {
|
||||
margin: 0;
|
||||
font-family: 'Playfair Display', sans-serif;
|
||||
font-weight: $bold;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------
|
||||
MOD: TIMELINE SPLIT
|
||||
----------------------------------------------*/
|
||||
|
||||
.timeline-split {
|
||||
@media (min-width: 768px) {
|
||||
.timeline {
|
||||
display: table;
|
||||
}
|
||||
.timeline-item {
|
||||
display: table-row;
|
||||
padding: 0;
|
||||
}
|
||||
.timeline-info,
|
||||
.timeline-marker,
|
||||
.timeline-content,
|
||||
.period .timeline-info {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
}
|
||||
.timeline-marker {
|
||||
position: relative;
|
||||
}
|
||||
.timeline-content {
|
||||
padding-left: 30px;
|
||||
}
|
||||
.timeline-info {
|
||||
padding-right: 30px;
|
||||
}
|
||||
.period .timeline-title {
|
||||
position: relative;
|
||||
left: -45px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------
|
||||
MOD: TIMELINE CENTERED
|
||||
----------------------------------------------*/
|
||||
|
||||
.timeline-centered {
|
||||
@extend .timeline-split;
|
||||
@media (min-width: 992px) {
|
||||
&,
|
||||
.timeline-item,
|
||||
.timeline-info,
|
||||
.timeline-marker,
|
||||
.timeline-content {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.timeline-item {
|
||||
padding-bottom: 40px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.timeline-marker {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -7.5px;
|
||||
}
|
||||
.timeline-info,
|
||||
.timeline-content {
|
||||
width: 50%;
|
||||
}
|
||||
> .timeline-item:nth-child(odd) .timeline-info {
|
||||
float: left;
|
||||
text-align: right;
|
||||
padding-right: 30px;
|
||||
}
|
||||
> .timeline-item:nth-child(odd) .timeline-content {
|
||||
float: right;
|
||||
text-align: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
> .timeline-item:nth-child(even) .timeline-info {
|
||||
float: right;
|
||||
text-align: left;
|
||||
padding-left: 30px;
|
||||
}
|
||||
> .timeline-item:nth-child(even) .timeline-content {
|
||||
float: left;
|
||||
text-align: right;
|
||||
padding-right: 30px;
|
||||
}
|
||||
> .timeline-item.period .timeline-content {
|
||||
float: none;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.timeline-item.period {
|
||||
padding: 50px 0 90px;
|
||||
}
|
||||
.period .timeline-marker:after {
|
||||
height: 30px;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
}
|
||||
.period .timeline-title {
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------
|
||||
MOD: MARKER OUTLINE
|
||||
----------------------------------------------*/
|
||||
|
||||
.marker-outline {
|
||||
.timeline-marker {
|
||||
&:before {
|
||||
background: transparent;
|
||||
border-color: $primary-blue;
|
||||
}
|
||||
}
|
||||
.timeline-item:hover .timeline-marker:before {
|
||||
background: $primary-blue;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
17
client/src/components/user/profile/update-form.vue
Normal file
17
client/src/components/user/profile/update-form.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<form>
|
||||
<div>Update profile for {{ user.name }}</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UpdateForm',
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,7 +1,7 @@
|
||||
import Navbar from './components/global/navbar/navbar'
|
||||
import Loader from './components/global/loader'
|
||||
import Navbar from './components/global/navbar/navbar';
|
||||
import Loader from './components/global/loader';
|
||||
|
||||
export default [
|
||||
Navbar,
|
||||
Loader
|
||||
]
|
||||
Navbar,
|
||||
Loader
|
||||
];
|
||||
@@ -1,93 +1,76 @@
|
||||
// Core
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import VueRouter from 'vue-router'
|
||||
import App from './app.vue'
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import App from './app.vue';
|
||||
import VueMeta from 'vue-meta';
|
||||
|
||||
import Globals from './global-components.js'
|
||||
Globals.forEach(component => {
|
||||
Vue.component(component.name, component)
|
||||
Vue.use(VueMeta, {
|
||||
// optional pluginOptions
|
||||
refreshOnceOnNavigation: true
|
||||
});
|
||||
|
||||
// Environment
|
||||
require('dotenv').config()
|
||||
|
||||
// Cookies
|
||||
import VueCookies from 'vue-cookies'
|
||||
Vue.use(VueCookies)
|
||||
Vue.$cookies.config('30d','','')
|
||||
|
||||
// Jquery
|
||||
import jquery from 'jquery'
|
||||
window.$ = jquery
|
||||
window.jquery = jquery
|
||||
|
||||
// Styles
|
||||
import './assets/scss/_global.scss'
|
||||
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)
|
||||
|
||||
import { VueMasonryPlugin } from 'vue-masonry'
|
||||
Vue.use(VueMasonryPlugin)
|
||||
|
||||
import clipboard from 'v-clipboard'
|
||||
Vue.use(clipboard)
|
||||
|
||||
// FUNCTIONS
|
||||
var filter = function(text, length, clamp){
|
||||
clamp = clamp || '...';
|
||||
var node = document.createElement('div');
|
||||
node.innerHTML = text;
|
||||
var content = node.textContent;
|
||||
return content.length > length ? content.slice(0, length) + clamp : content;
|
||||
}
|
||||
Vue.filter('truncate', filter)
|
||||
|
||||
// Router
|
||||
import router from './routes'
|
||||
Vue.use(VueRouter)
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
// Store
|
||||
Vue.use(Vuex)
|
||||
let user = Vue.$cookies.get('U_')
|
||||
import store from './store';
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state: user ?
|
||||
{ status: { loggedIn: true }, user }
|
||||
: { status: { loggedIn: false }, user: null },
|
||||
mutations: {
|
||||
loginSucceed (state, user) {
|
||||
state.status.loggedIn = true
|
||||
state.user = user
|
||||
},
|
||||
loginFail (state) {
|
||||
state.status.loggedIn = false
|
||||
state.user = null
|
||||
},
|
||||
logout(state) {
|
||||
state.status.loggedIn = false;
|
||||
state.user = null;
|
||||
},
|
||||
registerSucceed (state, user) {
|
||||
state.status.loggedIn = true
|
||||
state.user = user
|
||||
},
|
||||
registerFail (state) {
|
||||
state.status.loggedIn = false
|
||||
state.user = null
|
||||
},
|
||||
}
|
||||
})
|
||||
// Global components
|
||||
import Globals from './global-components.js';
|
||||
Globals.forEach(component => {
|
||||
Vue.component(component.name, component);
|
||||
});
|
||||
|
||||
// Cookies
|
||||
import VueCookies from 'vue-cookies';
|
||||
Vue.use(VueCookies);
|
||||
|
||||
// Jquery
|
||||
import jquery from 'jquery';
|
||||
window.$ = jquery;
|
||||
window.jquery = jquery;
|
||||
|
||||
// Styles
|
||||
// Fonts
|
||||
import './assets/scss/_fonts.scss';
|
||||
import './assets/scss/_global.scss';
|
||||
|
||||
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 (will probably get removed in the very very near future lmao)
|
||||
import { VueMasonryPlugin } from 'vue-masonry';
|
||||
Vue.use(VueMasonryPlugin);
|
||||
|
||||
// Clipboard (might find a better one or code it myself idk)
|
||||
import clipboard from 'v-clipboard';
|
||||
Vue.use(clipboard);
|
||||
|
||||
// FUNCTIONS
|
||||
// Let's be honest i will 1000% refactor this.
|
||||
let filter = (text, length, clamp) => {
|
||||
clamp = clamp || '...';
|
||||
let node = document.createElement('div');
|
||||
node.innerHTML = text;
|
||||
let content = node.textContent;
|
||||
return content.length > length ? content.slice(0, length) + clamp : content;
|
||||
};
|
||||
Vue.filter('truncate', filter);
|
||||
|
||||
// Router
|
||||
import router from './routes';
|
||||
Vue.use(VueRouter);
|
||||
|
||||
// Mount Vue
|
||||
const app = new Vue({
|
||||
render: h => h(App),
|
||||
router,
|
||||
store: store
|
||||
})
|
||||
app.$mount('#srs')
|
||||
render: h => h(App),
|
||||
router,
|
||||
store: store
|
||||
});
|
||||
app.$mount('#srs');
|
||||
|
||||
@@ -1,42 +1,47 @@
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main class="px-4">
|
||||
<h1 class="title text-dark mb-4 font-display line-height-100">"C'est magique, ta gueule."</h1>
|
||||
<div class="lead font-display font-weight-bold">— N'importe quel MJ, une fois dans sa vie</div>
|
||||
<hr class="w-50">
|
||||
<div class="lead"><span class="font-display">Auracle</span> est une base de données publique en ligne pour sortilèges, en soutien au jeu de rôle sur table <span class="font-weight-bold text-secondary">Leïm</span>.</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main class="px-4">
|
||||
<h1 class="title text-dark mb-4 font-display font-weight-black line-height-100">
|
||||
"C'est magique, ta gueule."
|
||||
</h1>
|
||||
<div class="lead font-display font-weight-bold">
|
||||
— N'importe quel MJ, une fois dans sa vie
|
||||
</div>
|
||||
<hr class="w-50">
|
||||
<div class="lead">
|
||||
<span class="font-display font-weight-bold">Auracle</span> est une base de données publique en ligne pour sortilèges, en soutien au jeu de rôle sur table <span class="font-weight-bold text-secondary">Leïm</span>.
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'index-page',
|
||||
}
|
||||
name: 'IndexPage',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
section {
|
||||
min-height: calc(100vh - 56px);
|
||||
main {
|
||||
width: 1000px;
|
||||
.title {
|
||||
font-size: 5rem;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
}
|
||||
.lead {
|
||||
.font-display {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
min-height: calc(100vh - 56px);
|
||||
main {
|
||||
width: 1000px;
|
||||
.title {
|
||||
font-size: 3.5rem;
|
||||
color: $white;
|
||||
font-size: 64px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: $bp-md) {
|
||||
section {
|
||||
main {
|
||||
.title {
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,23 @@
|
||||
<template>
|
||||
<div class="container-fluid p-4" id="spell-container">
|
||||
<h1 class="display-3 font-display mb-3">Écoles</h1>
|
||||
</div>
|
||||
<div
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h1 class="display-3 font-display mb-3">
|
||||
Écoles
|
||||
</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'schools-page'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'SchoolsPage',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Maîtrises'
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,46 +1,52 @@
|
||||
<template>
|
||||
<div class="container-fluid p-4" id="spell-container">
|
||||
<h1 class="display-3 font-display mb-3">{{ school.name }}</h1>
|
||||
<p>{{ school.description }}</p>
|
||||
<spell-list :school_id="id"/>
|
||||
</div>
|
||||
<div
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h1 class="display-3 font-display mb-3">
|
||||
{{ school.name }}
|
||||
</h1>
|
||||
<p>{{ school.description }}</p>
|
||||
<spell-list :school_id="id" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SpellsList from "~/components/spells/spells-list"
|
||||
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Schools = RepositoryFactory.get('schools')
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Schools = RepositoryFactory.get('schools');
|
||||
|
||||
import SpellsList from "@/components/spells/spells-list";
|
||||
|
||||
export default {
|
||||
name: 'single-school-page',
|
||||
components: {
|
||||
'spell-list': SpellsList,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
school: {},
|
||||
id: this.$route.params.id
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.computeSchool()
|
||||
},
|
||||
methods: {
|
||||
async fetchSchool(id) {
|
||||
const { data } = await Schools.getOne(id)
|
||||
return data
|
||||
},
|
||||
async computeSchool() {
|
||||
this.loading = true
|
||||
const displaySchool = await this.fetchSchool(this.id)
|
||||
this.loading = false
|
||||
this.school = displaySchool
|
||||
},
|
||||
}
|
||||
}
|
||||
name: 'SingleSchoolPage',
|
||||
metaInfo() {
|
||||
return {
|
||||
titleTemplate: `%s - ${this.school.name}`,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
'spell-list': SpellsList,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: this.$route.params.id,
|
||||
school: {},
|
||||
errors: {
|
||||
loading: "",
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
Schools.getOne(this.id)
|
||||
.then(v => {
|
||||
this.school = v.data;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -1,13 +1,48 @@
|
||||
<template>
|
||||
<div class="container-fluid p-4" id="spell-container">
|
||||
<h1 class="display-3 font-display mb-3">Sortilège</h1>
|
||||
</div>
|
||||
<div
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h1 class="display-3 font-display mb-3">
|
||||
{{ spell.name }}
|
||||
</h1>
|
||||
<p class="prewrap">
|
||||
{{ spell.description }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
// API
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Spells = RepositoryFactory.get('spells');
|
||||
|
||||
}
|
||||
export default {
|
||||
name: 'SingleSpellPage',
|
||||
metaInfo() {
|
||||
return {
|
||||
titleTemplate: this.spell.name ? `%s - ${this.spell.name}` : '%s',
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: this.$route.params.id,
|
||||
spell: {},
|
||||
errors: {
|
||||
loading: "",
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
Spells.getOne(this.id)
|
||||
.then(v => {
|
||||
this.spell = v.data;
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
<template>
|
||||
<div class="container-fluid p-4" id="spell-container">
|
||||
<h1 class="display-3 font-display mb-3">Sortilèges</h1>
|
||||
<spell-list/>
|
||||
</div>
|
||||
<div
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h1 class="display-3 font-display mb-3">
|
||||
Sortilèges
|
||||
</h1>
|
||||
<spell-list />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SpellsList from "~/components/spells/spells-list"
|
||||
import SpellsList from "@/components/spells/spells-list.vue";
|
||||
|
||||
export default {
|
||||
name: 'spells-page',
|
||||
components: {
|
||||
'spell-list': SpellsList,
|
||||
}
|
||||
export default {
|
||||
name: 'SpellsPage',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Grimoire'
|
||||
},
|
||||
components: {
|
||||
'spell-list': SpellsList,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
29
client/src/pages/timelines/timeline-page.vue
Normal file
29
client/src/pages/timelines/timeline-page.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<div
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h1 class="display-3 font-display mb-3">
|
||||
Chronologie
|
||||
</h1>
|
||||
<timeline />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Timeline from "@/components/timeline/timeline";
|
||||
|
||||
export default {
|
||||
name: 'TimelinePage',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Âges'
|
||||
},
|
||||
components: {
|
||||
'timeline': Timeline
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,92 +1,182 @@
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main>
|
||||
<div class="title font-display mb-3">Connexion</div>
|
||||
<form @submit="logUser">
|
||||
<div class="form-group">
|
||||
<label for="email">Addresse mail</label>
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
placeholder="john.doe@gmail.com"
|
||||
autocomplete="email">
|
||||
<small class="form-text text-muted">Votre addresse mail nous servira principalement à vous identifier et à retrouver votre compte si vous oubliez vos informations de connexion.</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
id="password"
|
||||
class="form-control"
|
||||
autocomplete="current-password">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Connexion</button>
|
||||
<router-link :to="'/inscription'" class="btn btn-dark">Inscription</router-link>
|
||||
<small class="form-text text-muted">Vous avez oublié votre mot de passe ? Cliquez-ici pour le changer !</small>
|
||||
</form>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main>
|
||||
<div class="title font-display mb-3">Connexion</div>
|
||||
|
||||
<form @submit="logUser">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Addresse mail</label>
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
:class="{ 'is-invalid': errors.email || errors.login }"
|
||||
placeholder="john.doe@gmail.com"
|
||||
autocomplete="email">
|
||||
|
||||
<small
|
||||
v-if="!errors.email"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
Votre addresse mail nous servira principalement à vous identifier et à retrouver votre compte si vous oubliez vos informations de connexion.
|
||||
</small>
|
||||
<small
|
||||
v-if="errors.email"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.email }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input
|
||||
v-model="password"
|
||||
type="password"
|
||||
id="password"
|
||||
class="form-control"
|
||||
:class="{ 'is-invalid': errors.password || errors.login }"
|
||||
autocomplete="current-password">
|
||||
<small
|
||||
v-if="!errors.password"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
Nous vous conseillons d'utiliser un mot de passe unique pour cette application seulement.
|
||||
</small>
|
||||
<small
|
||||
v-if="errors.password"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.password }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="remember_me"
|
||||
id="remember-me"
|
||||
class="form-check-input">
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="remember-me"
|
||||
>
|
||||
Rester connecté
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<small v-if="errors.login" class="text-danger">{{ errors.login }}</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Connexion</button>
|
||||
<router-link :to="'/inscription'" class="btn btn-dark">Inscription</router-link>
|
||||
<small class="form-text text-muted">Mot de passe oublié ? <a href="#">Vous pouvez le changer ici !</a></small>
|
||||
|
||||
</form>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Users = RepositoryFactory.get('users')
|
||||
|
||||
export default {
|
||||
name: 'login-page',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Connexion'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
email: "",
|
||||
password: "",
|
||||
submitted: false,
|
||||
errors: {
|
||||
login: ""
|
||||
}
|
||||
return {
|
||||
email: "",
|
||||
password: "",
|
||||
remember_me: false,
|
||||
submitted: false,
|
||||
|
||||
errors: {
|
||||
email: "",
|
||||
password: "",
|
||||
login: "",
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async logUser(e) {
|
||||
e.preventDefault()
|
||||
async logUser(e) {
|
||||
e.preventDefault();
|
||||
|
||||
Users.login({
|
||||
"mail": this.email,
|
||||
"password": this.password
|
||||
})
|
||||
.then(v => {
|
||||
let user = v.data.user
|
||||
this.$cookies.set("U_", user, 60 * 60 * 24 * 30)
|
||||
this.$store.commit('loginSucceed', user)
|
||||
this.$router.push('/profil')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$store.commit('loginFailed')
|
||||
})
|
||||
// Resets old errors if any
|
||||
for (const o in this.errors) {
|
||||
this.errors[o] = ""
|
||||
}
|
||||
this.submitted = true;
|
||||
|
||||
let userInput = {
|
||||
"user": {
|
||||
"mail": this.email,
|
||||
"password": this.password,
|
||||
},
|
||||
"remember_me": this.remember_me
|
||||
};
|
||||
|
||||
// Check is all inputs are set
|
||||
if (!userInput.user.mail) {
|
||||
this.errors.email = "Vous devez renseigner une addresse mail."
|
||||
}
|
||||
if (!userInput.user.password) {
|
||||
this.errors.password = "Vous devez renseigner un mot de passe."
|
||||
}
|
||||
|
||||
// Stops the method if any errors exist
|
||||
for (const o in this.errors) {
|
||||
if (this.errors[o] != "") {
|
||||
this.submitted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no errors are present, submits the form
|
||||
if (this.submitted) {
|
||||
this.$store.dispatch('user_login', userInput)
|
||||
.then(() => {
|
||||
this.$router.push('/profil')
|
||||
})
|
||||
.catch(err => {
|
||||
if (err.status != 500) {
|
||||
this.errors.email = err.data.error;
|
||||
} else {
|
||||
this.errors.login = err.data.error;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
section {
|
||||
min-height: calc(100vh - 56px);
|
||||
main {
|
||||
width: 600px;
|
||||
.title {
|
||||
font-size: 5rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
min-height: calc(100vh - 56px);
|
||||
main {
|
||||
width: 600px;
|
||||
.title {
|
||||
font-size: 3.5rem;
|
||||
font-size: 5rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
section {
|
||||
main {
|
||||
.title {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,24 +1,103 @@
|
||||
<template>
|
||||
<div class="container-fluid p-4" id="spell-container">
|
||||
<div class="display-3 font-display mb-3">
|
||||
<span class="username">{{ user.name }}</span>
|
||||
<span v-if="user.verified" class="verified"><i class="mad">check_circle</i></span>
|
||||
</div>
|
||||
<div
|
||||
v-if="user"
|
||||
id="spell-container"
|
||||
class="container-fluid p-4"
|
||||
>
|
||||
<h2 class="display-3 font-display mb-3">
|
||||
<span class="username">{{ user.name }}</span>
|
||||
</h2>
|
||||
<span>Membre depuis le {{ registered_date }}</span>
|
||||
|
||||
<ul
|
||||
id="tabs-tab"
|
||||
class="nav nav-tabs mt-3 mb-3"
|
||||
role="tablist"
|
||||
>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
id="tabs-home-tab"
|
||||
class="nav-link active"
|
||||
data-toggle="pill"
|
||||
href="#tabs-home"
|
||||
role="tab"
|
||||
aria-controls="tabs-home"
|
||||
aria-selected="true"
|
||||
>Mes sorts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
id="tabs-contact-tab"
|
||||
class="nav-link"
|
||||
data-toggle="pill"
|
||||
href="#tabs-contact"
|
||||
role="tab"
|
||||
aria-controls="tabs-contact"
|
||||
aria-selected="false"
|
||||
>Paramètres</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div
|
||||
id="tabs-tabContent"
|
||||
class="tab-content"
|
||||
>
|
||||
<div
|
||||
id="tabs-home"
|
||||
class="tab-pane fade show active"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tabs-home-tab"
|
||||
>
|
||||
...
|
||||
</div>
|
||||
<div
|
||||
id="tabs-contact"
|
||||
class="tab-pane fade"
|
||||
role="tabpanel"
|
||||
aria-labelledby="tabs-contact-tab"
|
||||
>
|
||||
<update-form :user="user" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import UpdateForm from '@/components/user/profile/update-form.vue';
|
||||
|
||||
export default {
|
||||
name: 'profile-page',
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.state.user
|
||||
}
|
||||
name: 'ProfilePage',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Profil'
|
||||
},
|
||||
components: {
|
||||
UpdateForm,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.getUserProfile;
|
||||
},
|
||||
}
|
||||
registered_date() {
|
||||
let raw_date = new Date(this.user.register_date);
|
||||
|
||||
let date_options = {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
};
|
||||
|
||||
return new Intl.DateTimeFormat("fr", date_options).format(raw_date);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.title {
|
||||
font-size: 5rem;
|
||||
font-weight: 700;
|
||||
@@ -28,4 +107,5 @@ export default {
|
||||
font-size: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,143 +1,198 @@
|
||||
<template>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main>
|
||||
<div class="title font-display mb-3">Inscription</div>
|
||||
<form @submit="registerUser">
|
||||
<div class="form-group">
|
||||
<label for="email">Pseudo</label>
|
||||
<input
|
||||
v-model="name"
|
||||
:class="{
|
||||
'is-invalid': errors.name,
|
||||
'is-valid': submitted && !errors.name }"
|
||||
type="text"
|
||||
id="username"
|
||||
class="form-control"
|
||||
placeholder="John Doe"
|
||||
autocomplete="username">
|
||||
<small v-if="!errors.name" class="form-text text-muted">Vous pouvez changer votre pseudo à tout moment.</small>
|
||||
<small v-if="errors.name" class="text-danger">{{ errors.name }}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Addresse mail</label>
|
||||
<input
|
||||
v-model="email"
|
||||
:class="{
|
||||
'is-invalid': errors.email,
|
||||
'is-valid': submitted && !errors.email }"
|
||||
type="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
placeholder="john.doe@gmail.com"
|
||||
autocomplete="email">
|
||||
<small v-if="!errors.email" class="form-text text-muted">Votre addresse mail nous servira principalement à vous identifier et à retrouver votre compte si vous oubliez vos informations de connexion.</small>
|
||||
<small v-if="errors.email" class="text-danger">{{ errors.email }}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input
|
||||
:class="{
|
||||
'is-invalid': errors.password,
|
||||
'is-valid': submitted && !errors.password }"
|
||||
v-model="password"
|
||||
type="password"
|
||||
id="password"
|
||||
class="form-control"
|
||||
autocomplete="password">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password_check">Confirmer le mot de passe</label>
|
||||
<input
|
||||
v-model="password_check"
|
||||
:class="{
|
||||
'is-invalid': errors.password_check || errors.password,
|
||||
'is-valid': submitted && !errors.password_check}"
|
||||
type="password"
|
||||
id="password_check"
|
||||
class="form-control"
|
||||
autocomplete="password-verification">
|
||||
<small v-if="!errors.password && !errors.password_check" class="form-text text-muted">Votre mot de passe doit idéalement contenir des symboles ainsi que des lettres et des chiffres.</small>
|
||||
<small v-if="errors.password" class="text-danger">{{ errors.password }}</small>
|
||||
<small v-if="errors.password_check" class="text-danger">{{ errors.password_check }}</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-dark">Inscription</button>
|
||||
</form>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<section class="d-flex justify-content-center align-items-center">
|
||||
<main>
|
||||
<div class="title font-display mb-3">Inscription</div>
|
||||
<form @submit="registerUser">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Nom d'utilisateur</label>
|
||||
<input
|
||||
v-model="name"
|
||||
:class="{
|
||||
'is-invalid': errors.name,
|
||||
'is-valid': submitted && !errors.name }"
|
||||
type="text"
|
||||
id="username"
|
||||
class="form-control"
|
||||
placeholder="John Doe"
|
||||
autocomplete="username">
|
||||
<small
|
||||
v-if="!errors.name"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
Vous pouvez changer votre pseudo à tout moment.
|
||||
</small>
|
||||
|
||||
<small
|
||||
v-if="errors.name"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.name }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Adresse mail</label>
|
||||
<input
|
||||
v-model="email"
|
||||
:class="{
|
||||
'is-invalid': errors.email,
|
||||
'is-valid': submitted && !errors.email }"
|
||||
type="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
placeholder="john.doe@gmail.com"
|
||||
autocomplete="email">
|
||||
<small
|
||||
v-if="!errors.email"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
Votre addresse mail nous servira principalement à vous identifier et à retrouver votre compte si vous oubliez vos informations de connexion.
|
||||
</small>
|
||||
|
||||
<small
|
||||
v-if="errors.email"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.email }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input
|
||||
:class="{
|
||||
'is-invalid': errors.password,
|
||||
'is-valid': submitted && !errors.password }"
|
||||
v-model="password"
|
||||
type="password"
|
||||
id="password"
|
||||
class="form-control"
|
||||
autocomplete="password">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password_check">Confirmer le mot de passe</label>
|
||||
<input
|
||||
v-model="password_check"
|
||||
:class="{
|
||||
'is-invalid': errors.password_check || errors.password,
|
||||
'is-valid': submitted && !errors.password_check}"
|
||||
type="password"
|
||||
id="password_check"
|
||||
class="form-control"
|
||||
autocomplete="password-verification">
|
||||
<small
|
||||
v-if="!errors.password && !errors.password_check"
|
||||
class="form-text text-muted"
|
||||
>
|
||||
Votre mot de passe doit idéalement contenir des symboles ainsi que des lettres et des chiffres.
|
||||
</small>
|
||||
|
||||
<small
|
||||
v-if="errors.password"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.password }}
|
||||
</small>
|
||||
<small
|
||||
v-if="errors.password_check"
|
||||
class="form-text text-danger"
|
||||
>
|
||||
{{ errors.password_check }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<small v-if="errors.register" class="text-danger">{{ errors.register }}</small>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-dark">Inscription</button>
|
||||
</form>
|
||||
</main>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// API
|
||||
import { RepositoryFactory } from "~/api/repositories"
|
||||
const Users = RepositoryFactory.get('users')
|
||||
|
||||
export default {
|
||||
name: 'register-page',
|
||||
data() {
|
||||
return {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
password_check: "",
|
||||
submitted: false,
|
||||
errors: {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
password_check: "",
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async registerUser(e) {
|
||||
e.preventDefault()
|
||||
|
||||
// Resets old errors if any
|
||||
for (const o in this.errors) {
|
||||
this.errors[o] = ""
|
||||
}
|
||||
this.submitted = true
|
||||
|
||||
if (!this.name) {
|
||||
this.errors.name = "Vous devez renseigner un pseudonyme."
|
||||
}
|
||||
if (!this.email) {
|
||||
this.errors.email = "Vous devez renseigner une addresse mail."
|
||||
}
|
||||
if (!this.password) {
|
||||
this.errors.password = "Vous devez renseigner un mot de passe."
|
||||
}
|
||||
if ((this.password.localeCompare(this.password_check)) != 0) {
|
||||
this.errors.password_check = "Les mots de passe ne correspondent pas."
|
||||
}
|
||||
|
||||
// Stops the method if any errors exist
|
||||
for (const o in this.errors) {
|
||||
if (this.errors[o]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
Users.register({
|
||||
"name": this.name,
|
||||
"mail": this.email,
|
||||
"password": this.password
|
||||
})
|
||||
.then(v => {
|
||||
let user = v.data.user
|
||||
this.$cookies.set("U_", user, 60 * 60 * 24 * 30)
|
||||
this.$store.commit('registerSucceed', user)
|
||||
this.$router.push('/profil')
|
||||
})
|
||||
.catch(err => {
|
||||
let error = err.response.data.error
|
||||
this.errors.email = error
|
||||
this.$store.commit('registerFail')
|
||||
})
|
||||
}
|
||||
name: 'register-page',
|
||||
metaInfo: {
|
||||
titleTemplate: '%s - Inscription'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
password_check: "",
|
||||
submitted: false,
|
||||
errors: {
|
||||
name: "",
|
||||
email: "",
|
||||
password: "",
|
||||
password_check: "",
|
||||
register: "",
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async registerUser(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Resets old errors if any
|
||||
for (const o in this.errors) {
|
||||
this.errors[o] = ""
|
||||
}
|
||||
this.submitted = true;
|
||||
|
||||
let userInput = {
|
||||
"user": {
|
||||
"name": this.name,
|
||||
"mail": this.email,
|
||||
"password": this.password
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all inputs are valid without sending anything
|
||||
if (!userInput.user.name) {
|
||||
this.errors.name = "Vous devez renseigner un pseudonyme."
|
||||
}
|
||||
if (!userInput.user.mail) {
|
||||
this.errors.email = "Vous devez renseigner une addresse mail."
|
||||
}
|
||||
if (!userInput.user.password) {
|
||||
this.errors.password = "Vous devez renseigner un mot de passe."
|
||||
}
|
||||
if ((userInput.user.password.localeCompare(this.password_check)) != 0) {
|
||||
this.errors.password_check = "Les mots de passe ne correspondent pas."
|
||||
}
|
||||
|
||||
// Stops the method if any errors exist
|
||||
for (const o in this.errors) {
|
||||
if (this.errors[o] != "") {
|
||||
this.submitted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no errors are present, submits the form
|
||||
if (this.submitted) {
|
||||
this.$store.dispatch('user_register', userInput)
|
||||
.then(() => {
|
||||
this.$router.push('/');
|
||||
})
|
||||
.catch(err => {
|
||||
// Sets errors in case something wrong comes back from the API
|
||||
if (err.status === 409) {
|
||||
this.errors.email = err.data.error;
|
||||
} else {
|
||||
this.errors.register = "Une erreur inconnue est survenue, rééssayez plus tard.";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,91 +1,102 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import VueRouter from 'vue-router';
|
||||
|
||||
import store from './store';
|
||||
|
||||
// Pages
|
||||
import Index from "~/pages/index-page"
|
||||
import Index from "@/pages/index-page";
|
||||
|
||||
import Spells from "~/pages/spells/spells-page"
|
||||
import SpellSingle from "~/pages/spells/single-spell-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 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"
|
||||
import Profile from "~/pages/user/profile-page"
|
||||
import Timeline from "./pages/timelines/timeline-page";
|
||||
|
||||
import Profile from "@/pages/user/profile-page";
|
||||
import Login from "@/pages/user/login-page";
|
||||
import Register from "@/pages/user/register-page";
|
||||
|
||||
// Routes
|
||||
const routes = [
|
||||
{
|
||||
path: "*",
|
||||
redirect: "/",
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: Index,
|
||||
},
|
||||
{
|
||||
path: '/connexion',
|
||||
component: Login,
|
||||
meta: {
|
||||
antiAuthGuard: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/inscription',
|
||||
component: Register,
|
||||
meta: {
|
||||
antiAuthGuard: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sorts',
|
||||
component: Spells,
|
||||
},
|
||||
{
|
||||
path: '/sorts/:id',
|
||||
component: SpellSingle,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/ecoles',
|
||||
component: Schools,
|
||||
},
|
||||
{
|
||||
path: '/ecoles/:id',
|
||||
component: SchoolSingle,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/profil',
|
||||
component: Profile,
|
||||
props: true,
|
||||
meta: {
|
||||
authGuard: true,
|
||||
}
|
||||
},
|
||||
]
|
||||
{
|
||||
path: "*",
|
||||
redirect: "/",
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: Index,
|
||||
},
|
||||
{
|
||||
path: '/connexion',
|
||||
component: Login,
|
||||
meta: {
|
||||
loginFilter: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/inscription',
|
||||
component: Register,
|
||||
meta: {
|
||||
loginFilter: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/sorts',
|
||||
component: Spells,
|
||||
},
|
||||
{
|
||||
path: '/sorts/:id',
|
||||
component: SpellSingle,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/ecoles',
|
||||
component: Schools,
|
||||
},
|
||||
{
|
||||
path: '/ecoles/:id',
|
||||
component: SchoolSingle,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: '/ages',
|
||||
component: Timeline,
|
||||
},
|
||||
{
|
||||
path: '/profil',
|
||||
component: Profile,
|
||||
props: true,
|
||||
meta: {
|
||||
logoutFilter: true,
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
routes,
|
||||
linkActiveClass: "",
|
||||
linkExactActiveClass: "active",
|
||||
})
|
||||
mode: 'history',
|
||||
routes,
|
||||
linkActiveClass: "",
|
||||
linkExactActiveClass: "active",
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.matched.some(record => record.meta.authGuard)) {
|
||||
if (Vue.$cookies.get('U_') == null) {
|
||||
next({
|
||||
path: '/connexion',
|
||||
params: { nextUrl: to.fullPath },
|
||||
})
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
} else {
|
||||
next()
|
||||
if (to.matched.some(record => record.meta.loginFilter)) {
|
||||
if (store.getters.getUserProfile) {
|
||||
next({
|
||||
path: '/',
|
||||
});
|
||||
}
|
||||
})
|
||||
next();
|
||||
} else if (to.matched.some(record => record.meta.logoutFilter)) {
|
||||
if (!store.getters.getUserProfile) {
|
||||
next({
|
||||
path: '/connexion',
|
||||
});
|
||||
}
|
||||
next();
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
export default router;
|
||||
19
client/src/store/index.js
Normal file
19
client/src/store/index.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import VueCookies from 'vue-cookies';
|
||||
Vue.use(VueCookies);
|
||||
Vue.$cookies.config('30d','','');
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
import user from './modules/user.store';
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
user
|
||||
},
|
||||
strict: debug
|
||||
});
|
||||
23
client/src/store/modules/spell.store.js
Normal file
23
client/src/store/modules/spell.store.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const state = {
|
||||
|
||||
};
|
||||
|
||||
const getters = {
|
||||
|
||||
};
|
||||
|
||||
const actions = {
|
||||
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
91
client/src/store/modules/user.store.js
Normal file
91
client/src/store/modules/user.store.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import cookie from 'vue-cookies';
|
||||
|
||||
// API
|
||||
import { RepositoryFactory } from "@/api/repositories";
|
||||
const Users = RepositoryFactory.get('users');
|
||||
|
||||
export const namespaced = true;
|
||||
|
||||
const state = {
|
||||
profile: cookie.get('user_profile') || null,
|
||||
};
|
||||
|
||||
const getters = {
|
||||
getUserProfile: state => {
|
||||
return state.profile;
|
||||
}
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
loginUser(state, user) {
|
||||
state.profile = user;
|
||||
},
|
||||
|
||||
logoutUser(state) {
|
||||
state.profile = null;
|
||||
},
|
||||
|
||||
registerUser() {
|
||||
// Will contain the email call eventually
|
||||
}
|
||||
};
|
||||
|
||||
const actions = {
|
||||
/**
|
||||
* @param data
|
||||
* An object containing :
|
||||
* - user object with mail and password hash properties
|
||||
* - remember_me boolean to check cookie expiration time
|
||||
*/
|
||||
user_login ({ commit }, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Users.login(data.user)
|
||||
.then(v => {
|
||||
let user = v.data.user;
|
||||
|
||||
// Check if the use wishes to be remembered
|
||||
if (data.remember_me) {
|
||||
cookie.set('user_profile', user, 60 * 60 * 24 * 30); // Expires after a month
|
||||
} else {
|
||||
cookie.set('user_profile', user, 0); // Expires after browser session expires
|
||||
}
|
||||
|
||||
commit('loginUser', user);
|
||||
resolve(user);
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err.response);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
user_logout ({ commit }) {
|
||||
cookie.remove('user_profile');
|
||||
commit('logoutUser');
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* An object containing :
|
||||
* - user object with string mail, string name, and string password
|
||||
*/
|
||||
user_register ({ commit }, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Users.register(data.user)
|
||||
.then(() => {
|
||||
commit('registerUser');
|
||||
resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err.response);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
@@ -1,11 +1,19 @@
|
||||
const path = require('path')
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
configureWebpack: {
|
||||
resolve: {
|
||||
alias: {
|
||||
"~": path.resolve(__dirname, 'src/')
|
||||
}
|
||||
}
|
||||
lintOnSave: false,
|
||||
configureWebpack: {
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, 'src/')
|
||||
}
|
||||
}
|
||||
},
|
||||
css: {
|
||||
loaderOptions: {
|
||||
scss: {
|
||||
prependData: `@import "@/assets/scss/_variables.scss";`
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,176 +0,0 @@
|
||||
DROP DATABASE IF EXISTS auracle;
|
||||
CREATE DATABASE auracle CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
USE auracle;
|
||||
|
||||
/* =========== 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,
|
||||
`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,
|
||||
`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",
|
||||
`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,
|
||||
`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 */
|
||||
CREATE TABLE IF NOT EXISTS `meta_school` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Nom de l'école mère",
|
||||
`description` VARCHAR(255) DEFAULT "Description de l'école mère",
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
/* SCHOOLS */
|
||||
CREATE TABLE IF NOT EXISTS `school` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL DEFAULT "Nom de l'école",
|
||||
`description` VARCHAR(255) DEFAULT "Description de l'école",
|
||||
`meta_school_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
FOREIGN KEY(`meta_school_id`) REFERENCES meta_school(`id`)
|
||||
);
|
||||
|
||||
/* COMMON INGREDIENTS */
|
||||
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 encore chaude.",
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
/* COMMON VARIABLES */
|
||||
CREATE TABLE IF NOT EXISTS `variable` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT "Nombre de créatures affectées",
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
/* ==== ASSOCIATION TABLES ==== */
|
||||
|
||||
/* SPELLS' SCHOOLS */
|
||||
/* One spell can have multiple (up to 3) schools */
|
||||
CREATE TABLE IF NOT EXISTS `spell_school` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`school_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `school_id`),
|
||||
FOREIGN KEY(`spell_id`) REFERENCES spell(`id`),
|
||||
FOREIGN KEY(`school_id`) REFERENCES school(`id`)
|
||||
);
|
||||
|
||||
/* SPELLS' VARIABLES */
|
||||
/* One spell can have multiple (up to 2) variables of cost */
|
||||
CREATE TABLE IF NOT EXISTS `spell_variable` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`variable_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `variable_id`),
|
||||
FOREIGN KEY(`spell_id`) REFERENCES spell(`id`),
|
||||
FOREIGN KEY(`variable_id`) REFERENCES variable(`id`)
|
||||
);
|
||||
|
||||
/* SPELLS' VARIABLES */
|
||||
/* One spell can have multiple ingredients */
|
||||
CREATE TABLE IF NOT EXISTS `spell_ingredient` (
|
||||
`spell_id` INT UNSIGNED NOT NULL,
|
||||
`ingredient_id` INT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY (`spell_id`, `ingredient_id`),
|
||||
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, '<l>', '\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, 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.");
|
||||
|
||||
-- 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');
|
||||
@@ -1,37 +0,0 @@
|
||||
USE auracle;
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
@@ -1,18 +0,0 @@
|
||||
// MODULES
|
||||
const fs = require('fs')
|
||||
const mysql = require('mysql')
|
||||
|
||||
// Setting up the database connection
|
||||
const knex = require('knex')({
|
||||
client: "mysql",
|
||||
connection: {
|
||||
host : process.env.DB_HOST,
|
||||
user : process.env.DB_USER,
|
||||
password : process.env.DB_PASSWORD,
|
||||
database : "auracle",
|
||||
charset : "utf8"
|
||||
},
|
||||
})
|
||||
const bookshelf = require('bookshelf')(knex)
|
||||
|
||||
module.exports = { bookshelf }
|
||||
48
functions.js
48
functions.js
@@ -1,48 +0,0 @@
|
||||
// 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
|
||||
}
|
||||
60
index.js
60
index.js
@@ -1,60 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// MODULES
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
const helmet = require('helmet')
|
||||
const morgan = require('morgan')
|
||||
const cors = require('cors') // module to format the json response
|
||||
const dotenv = require('dotenv').config()
|
||||
|
||||
// Creates instances of database connections
|
||||
const connection = require('./database/bookshelf')
|
||||
const db = connection.db
|
||||
|
||||
// CONSTANTS
|
||||
const port = 2814
|
||||
|
||||
// Import routes
|
||||
const routes = require('./routes')
|
||||
|
||||
// Builds app w/ express
|
||||
let app = express()
|
||||
app.use(bodyParser.json({ limit: '10kb' }))
|
||||
app.use(cors())
|
||||
app.use(morgan('tiny'))
|
||||
app.use(helmet())
|
||||
|
||||
// Serves
|
||||
const server = app.listen( port, () => {console.log(`App listening on port ${port}`)})
|
||||
|
||||
// Get credentials
|
||||
// app.get('/api/login', (req, res, next) => {
|
||||
// if (req.headers.auracle_key !== process.env.API_KEY_PUBLIC) {
|
||||
// return res.status(401).send('Credentials error !')
|
||||
// } else {
|
||||
// return res.status(200).send(JSON.stringify(
|
||||
// {
|
||||
// "secret_key": process.env.API_KEY_PRIVATE,
|
||||
// })
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
|
||||
// Auth guard
|
||||
const authguard = (req, res, next) => {
|
||||
if (req.headers.auracle_key !== process.env.API_KEY_PUBLIC) {
|
||||
return res.status(401).send('The API key is either missing or incorrect.')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
// Routing
|
||||
app.use('/api/spells', authguard,routes.spells)
|
||||
app.use('/api/schools', authguard, routes.schools)
|
||||
app.use('/api/meta_schools', authguard, routes.meta_schools)
|
||||
app.use('/api/variables', authguard, routes.variables)
|
||||
app.use('/api/ingredients', authguard, routes.ingredients)
|
||||
app.use('/api/users', authguard, routes.users)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
require('./spell-model')
|
||||
|
||||
let Ingredient = bookshelf.Model.extend({
|
||||
tableName: 'ingredient',
|
||||
spells() {
|
||||
return this.belongsToMany( 'Spell', 'spell_ingredient')
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('Ingredient', Ingredient)
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
require('./school-model')
|
||||
|
||||
let MetaSchool = bookshelf.Model.extend({
|
||||
tableName: 'meta_school',
|
||||
schools() {
|
||||
return this.hasMany( 'School' )
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('MetaSchool', MetaSchool)
|
||||
@@ -1,17 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
require('./spell-model')
|
||||
require('./meta-school-model')
|
||||
|
||||
let School = bookshelf.Model.extend({
|
||||
tableName: 'school',
|
||||
spells() {
|
||||
return this.belongsToMany( 'Spell', 'spell_school' )
|
||||
},
|
||||
meta_schools() {
|
||||
return this.belongsTo( 'MetaSchool', 'meta_school_id' )
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('School', School)
|
||||
@@ -1,21 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
require('./school-model')
|
||||
require('./variable-model')
|
||||
require('./ingredient-model')
|
||||
|
||||
let Spell = bookshelf.Model.extend({
|
||||
tableName: 'spell',
|
||||
schools() {
|
||||
return this.belongsToMany( 'School', 'spell_school' )
|
||||
},
|
||||
variables() {
|
||||
return this.belongsToMany( 'Variable', 'spell_variable' )
|
||||
},
|
||||
ingredients() {
|
||||
return this.belongsToMany( 'Ingredient', 'spell_ingredient' )
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('Spell', Spell)
|
||||
@@ -1,9 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
let User = bookshelf.Model.extend({
|
||||
tableName: 'user',
|
||||
hidden: ['id', 'password']
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('User', User)
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
|
||||
require('./spell-model')
|
||||
|
||||
let Variable = bookshelf.Model.extend({
|
||||
tableName: 'variable',
|
||||
spells() {
|
||||
return this.belongsToMany( 'Spell', 'spell_variable')
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = bookshelf.model('Variable', Variable)
|
||||
2433
package-lock.json
generated
2433
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "auracle-api",
|
||||
"version": "1.0.0",
|
||||
"description": "API for Auracle database",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"api": "node index.js",
|
||||
"client": "cd client && npm run serve"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/AlexisNP/spellsaurus.git"
|
||||
},
|
||||
"keywords": [
|
||||
"api",
|
||||
"rpg",
|
||||
"spells",
|
||||
"magic",
|
||||
"database",
|
||||
"ttrpg",
|
||||
"dices",
|
||||
"worldbuilding"
|
||||
],
|
||||
"author": "AlexisNP",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/AlexisNP/spellsaurus/issues"
|
||||
},
|
||||
"homepage": "https://github.com/AlexisNP/spellsaurus#readme",
|
||||
"dependencies": {
|
||||
"bcrypt": "^4.0.1",
|
||||
"bookshelf": "^1.1.1",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"helmet": "^3.22.0",
|
||||
"jsonschema": "^1.2.6",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"knex": "^0.21.1",
|
||||
"morgan": "^1.10.0",
|
||||
"mysql": "^2.18.1",
|
||||
"uuid": "^8.2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/ingredient-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const v = new Validator()
|
||||
const IngredientValidation = require("../validations/IngredientValidation")
|
||||
v.addSchema(IngredientValidation, "/IngredientValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
// Error handling
|
||||
const { HttpError } = require('../validations/Errors')
|
||||
|
||||
class IngredientRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.fetchAll({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get ingredients"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['spells']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get ingredient"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get ingredient"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addOne(igr) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
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 (isXSSAttempt(igr.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return model.forge({
|
||||
'name': igr.name,
|
||||
'description': igr.description,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Insert Ingredient error"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 (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 (isXSSAttempt(igr.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
model.forge({id: id})
|
||||
.fetch({require: true, withRelated: ['spells']})
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': igr.name,
|
||||
'description': igr.description,
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Update Ingredient error"))
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get ingredient"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({require: true, withRelated: ['spells']})
|
||||
.then(v => {
|
||||
v.spells().detach()
|
||||
v.destroy()
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'Ingredient with ID ' + id + ' successfully deleted !'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get ingredient"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IngredientRepository
|
||||
@@ -1,53 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/meta-school-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const v = new Validator()
|
||||
const MetaSchoolValidation = require("../validations/MetaSchoolValidation")
|
||||
v.addSchema(MetaSchoolValidation, "/MetaSchoolValidation")
|
||||
|
||||
// Validations
|
||||
const regexXSS = RegExp(/<[^>]*script/)
|
||||
|
||||
// Error handling
|
||||
const { HttpError } = require('../validations/Errors')
|
||||
|
||||
class MetaSchoolRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.fetchAll({ withRelated: ['schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get meta schools"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['schools']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get meta school"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MetaSchoolRepository
|
||||
@@ -1,172 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/school-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const v = new Validator()
|
||||
const SchoolValidation = require("../validations/SchoolValidation")
|
||||
v.addSchema(SchoolValidation, "/SchoolValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
// Error handling
|
||||
const { HttpError } = require('../validations/Errors')
|
||||
|
||||
class SchoolRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.fetchAll({ withRelated: ['meta_schools'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get schools"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['meta_schools']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get school"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get spells from school"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addOne(s) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
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 (isXSSAttempt(s.name) || isXSSAttempt(s.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return model.forge({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'meta_school_id': s.meta_school_id,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['meta_schools'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Insert School error"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 (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 (isXSSAttempt(s.name) || isXSSAttempt(s.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
model.forge({id: id})
|
||||
.fetch({require: true, withRelated: ['meta_schools']})
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'meta_school_id': s.meta_school_id
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['meta_schools'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Update School error"))
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get school"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({require: true, withRelated: ['spells', 'meta_schools']})
|
||||
.then(v => {
|
||||
v.spells().detach()
|
||||
v.destroy()
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'School with ID ' + id + ' successfully deleted !'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get school"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SchoolRepository
|
||||
@@ -1,282 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/spell-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const v = new Validator()
|
||||
const SpellValidation = require("../validations/SpellValidation")
|
||||
v.addSchema(SpellValidation, "/SpellValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
// Error handling
|
||||
const { HttpError } = require('../validations/Errors')
|
||||
|
||||
class SpellRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll(name, description, level, charge, cost, ritual) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let query = model.forge()
|
||||
|
||||
console.log("science")
|
||||
|
||||
if (name) { query.where('name', 'like', `%${name}%`) }
|
||||
if (description) { query.where('description', 'like', `%${description}%`) }
|
||||
if (level) { query.where({ 'level' : level }) }
|
||||
if (charge) { query.where({ 'charge' : charge }) }
|
||||
if (cost) { query.where({ 'cost' : cost }) }
|
||||
if (ritual) { query.where({ 'is_ritual' : ritual }) }
|
||||
|
||||
query.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 spells"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getAllPublic(name, description, level, charge, cost, ritual) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let query = model.forge()
|
||||
.where({ 'public' : 1 })
|
||||
|
||||
if (name) { query.where('name', 'like', `%${name}%`) }
|
||||
if (description) { query.where('description', 'like', `%${description}%`) }
|
||||
if (level) { query.where({ 'level' : level }) }
|
||||
if (charge) { query.where({ 'charge' : charge }) }
|
||||
if (cost) { query.where({ 'cost' : cost }) }
|
||||
if (ritual) { query.where({ 'is_ritual' : ritual }) }
|
||||
|
||||
query.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()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ 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 spell"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addOne(s) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
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 (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return model.forge({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'level': s.level,
|
||||
'charge' : s.charge,
|
||||
'cost' : s.cost,
|
||||
'is_ritual' : s.is_ritual
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.schools()
|
||||
.attach(s.schools, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.variables()
|
||||
.attach(s.variables, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.ingredients()
|
||||
.attach(s.ingredients, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['schools.meta_schools', 'variables', 'ingredients'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Insert Spell error"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 (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 (isXSSAttempt(s.name) || isXSSAttempt(s.description) || isXSSAttempt(s.cost)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
model.forge({id: id})
|
||||
.fetch({require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients']})
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'name': s.name,
|
||||
'description': s.description,
|
||||
'level': s.level,
|
||||
'charge' : s.charge,
|
||||
'cost' : s.cost,
|
||||
'is_ritual' : s.is_ritual
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
// Detaches AND attaches pivot tables, dw about it
|
||||
.tap(spell => {
|
||||
if (s.schools) {
|
||||
let schools = spell.related('school');
|
||||
return spell.schools().detach(schools, { transacting: t});
|
||||
}
|
||||
return
|
||||
})
|
||||
.tap(spell => {
|
||||
if (s.variables) {
|
||||
let variables = spell.related('variable');
|
||||
return spell.variables().detach(variables, { transacting: t});
|
||||
}
|
||||
return
|
||||
})
|
||||
.tap(spell => {
|
||||
if (s.ingredients) {
|
||||
let ingredients = spell.related('ingredient');
|
||||
return spell.ingredients().detach(ingredients, { transacting: t});
|
||||
}
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.schools()
|
||||
.attach(s.schools, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.variables()
|
||||
.attach(s.variables, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.tap(spell => {
|
||||
return spell
|
||||
.ingredients()
|
||||
.attach(s.ingredients, {
|
||||
transacting: t
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['schools.meta_schools', 'variables', 'ingredients'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Update Spell error"))
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get spell"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({require: true, withRelated: ['schools.meta_schools', 'variables', 'ingredients']})
|
||||
.then(v => {
|
||||
v.schools().detach()
|
||||
v.variables().detach()
|
||||
v.ingredients().detach()
|
||||
v.destroy()
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'Spell with ID ' + id + ' successfully deleted !'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get spell"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SpellRepository
|
||||
@@ -1,180 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
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
|
||||
const v = new Validator()
|
||||
const UserValidation = require("../validations/UserValidation")
|
||||
v.addSchema(UserValidation, "/UserValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
class UserRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.fetchAll()
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "Database error, couldn't get all users.",
|
||||
"code": 500
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOneByUUID(uuid, full) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'uuid' : uuid })
|
||||
.fetch()
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true, visibility: !full }))
|
||||
})
|
||||
.catch(err => {
|
||||
reject({
|
||||
"message": "User with this UUID was not found.",
|
||||
"code": 404
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getOneByEmail(mail, full) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'mail': mail })
|
||||
.fetch()
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true, visibility: !full }))
|
||||
})
|
||||
.catch(() => {
|
||||
reject({
|
||||
"message": "User with this email was not found.",
|
||||
"code": 404
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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({
|
||||
"message": "Request body cannot be empty.",
|
||||
"code": 403
|
||||
})
|
||||
} else if (!v.validate(u, UserValidation).valid) {
|
||||
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({
|
||||
"message": "Injection attempt detected, aborting the request.",
|
||||
"code": 403
|
||||
})
|
||||
} else {
|
||||
let hash = await bcrypt.hash(u.password, 10)
|
||||
let uuid = uuidv4()
|
||||
|
||||
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 => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
return this.getOneByUUID(uuid, false)
|
||||
})
|
||||
.then(newUser => {
|
||||
resolve({
|
||||
"message": "Account successfully created !",
|
||||
"user": newUser,
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
resolve({
|
||||
"message": "An error has occured while creating your account.",
|
||||
"code": 500,
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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)
|
||||
delete fetchedUser.id
|
||||
delete fetchedUser.password
|
||||
|
||||
if (match) {
|
||||
resolve({
|
||||
"message": "User successfully logged in !",
|
||||
"user": fetchedUser,
|
||||
})
|
||||
} else {
|
||||
reject({
|
||||
"message": "Les informations de connexion sont erronées.",
|
||||
})
|
||||
}
|
||||
})
|
||||
.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({
|
||||
"message": "L'email est déjà utilisé par un autre utilisateur.",
|
||||
"code": 403
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserRepository
|
||||
@@ -1,168 +0,0 @@
|
||||
'use strict'
|
||||
// Bookshelf
|
||||
const bookshelf = require('../database/bookshelf').bookshelf
|
||||
const model = require('../models/variable-model')
|
||||
|
||||
// Model validation
|
||||
const Validator = require('jsonschema').Validator
|
||||
const v = new Validator()
|
||||
const VariableValidation = require("../validations/VariableValidation")
|
||||
v.addSchema(VariableValidation, "/VariableValidation")
|
||||
|
||||
// Validations
|
||||
const isXSSAttempt = require('../functions').isXSSAttempt
|
||||
const isEmptyObject = require('../functions').isEmptyObject
|
||||
|
||||
// Error handling
|
||||
const { HttpError } = require('../validations/Errors')
|
||||
class VariableRepository {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.fetchAll({ withRelated: ['spells'] })
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get variables"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
getOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['spells']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get variable"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getSpellsFromOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({ withRelated: ['spells', 'spells.schools', 'spells.variables', 'spells.ingredients', 'spells.schools.meta_schools']})
|
||||
.then(v => {
|
||||
resolve(v.toJSON({ omitPivot: true }))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Couldn't get variable"))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
addOne(vr) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Checks if body exists and if the model fits, and throws errors if it doesn't
|
||||
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 (isXSSAttempt(vr.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
bookshelf.transaction(t => {
|
||||
return model.forge({
|
||||
'description': vr.description,
|
||||
}).save(null, {
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Insert Variable error"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 (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 (isXSSAttempt(vr.description)) {
|
||||
reject(new HttpError(403, 'Injection attempt detected, aborting the request.'))
|
||||
} else {
|
||||
model.forge({id: id})
|
||||
.fetch({require: true, withRelated: ['spells']})
|
||||
.then(v => {
|
||||
bookshelf.transaction(t => {
|
||||
return v.save({
|
||||
'description': vr.description,
|
||||
}, {
|
||||
method: 'update',
|
||||
transacting: t
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
throw err
|
||||
})
|
||||
})
|
||||
.then(v => {
|
||||
return v.load(['spells'])
|
||||
})
|
||||
.then(v => {
|
||||
resolve(this.getOne(v.id))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(500, "Update Variable error"))
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get variable"))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deleteOne(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
model.forge()
|
||||
.where({ 'id' : id })
|
||||
.fetch({require: true, withRelated: ['spells']})
|
||||
.then(v => {
|
||||
v.spells().detach()
|
||||
v.destroy()
|
||||
})
|
||||
.then(() => {
|
||||
resolve({
|
||||
'message': 'Variable with ID ' + id + ' successfully deleted !'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
reject(new HttpError(404, "Couldn't get variable"))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VariableRepository
|
||||
@@ -1,15 +0,0 @@
|
||||
const spells = require('./spells')
|
||||
const schools = require('./schools')
|
||||
const meta_schools = require('./meta_schools')
|
||||
const variables = require('./variables')
|
||||
const ingredients = require('./ingredients')
|
||||
const users = require('./users')
|
||||
|
||||
module.exports = {
|
||||
spells,
|
||||
schools,
|
||||
meta_schools,
|
||||
ingredients,
|
||||
variables,
|
||||
users,
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user