Finished TP

master
Devin Ivy 2021-04-11 23:24:17 -04:00 committed by cemal
parent 65fae52da5
commit 50452658cb
28 changed files with 1991 additions and 45 deletions

3
.env Normal file
View File

@ -0,0 +1,3 @@
EMAIL_USER=adeline.ondricka5@ethereal.email
EMAIL_PASSWORD=B4khRtXZPNqtr58bAu
EMAIL_FROM=adeline.ondricka5@ethereal.email

3
lib/auth/default.js Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = 'jwt';

View File

@ -0,0 +1,24 @@
'use strict';
module.exports = {
scheme: 'jwt',
options: {
keys: 'random_string',
verify: {
aud: 'urn:audience:iut',
iss: 'urn:issuer:iut',
sub: false,
nbf: true,
exp: true,
maxAgeSec: 14400, // 4 hours
timeSkewSec: 15
},
validate: async (artifacts, request, h) => {
return {
isValid: true,
credentials: artifacts.decoded.payload
};
}
}
};

View File

@ -0,0 +1,19 @@
// Migration pour créer la table des favoris
'use strict';
module.exports = {
async up(knex) {
await knex.schema.createTable('favorites', (table) => {
table.integer('user_id').unsigned().notNullable();
table.integer('movie_id').unsigned().notNullable();
table.primary(['user_id', 'movie_id']);
table.foreign('user_id').references('id').inTable('user');
table.foreign('movie_id').references('id').inTable('movie');
});
},
async down(knex) {
await knex.schema.dropTable('favorites');
}
}

22
lib/migrations/0-user.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
module.exports = {
async up(knex) {
//update table User for role
await knex.schema.table('user', (table) => {
table.string('role').notNullable().defaultTo('user');
});
},
async down(knex) {
//update table User for role
await knex.schema.table('user', (table) => {
table.dropColumn('role');
});
}
};

22
lib/migrations/1-user.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
module.exports = {
async up(knex) {
//update table User for role
await knex.schema.table('user', (table) => {
table.string('role').notNullable().defaultTo('user');
});
},
async down(knex) {
//update table User for role
await knex.schema.table('user', (table) => {
table.dropColumn('role');
});
}
};

23
lib/migrations/2-user.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
module.exports = {
async up(knex) {
// Add the "scope" field to the "user" table
await knex.schema.table('user', (table) => {
table.dropColumn('scope'); // Remove the "role" field
table.string('scope').notNullable().defaultTo('user');
});
},
async down(knex) {
// Revert the changes made in the "up" function
await knex.schema.table('user', (table) => {
table.dropColumn('scope');
table.string('scope').notNullable().defaultTo('user');
});
}
};

21
lib/migrations/3-user.js Normal file
View File

@ -0,0 +1,21 @@
'use strict';
module.exports = {
async up(knex) {
// Add the "scope" field to the "user" table
await knex.schema.table('user', (table) => {
table.dropColumn('scope'); // Remove the "role" field
});
},
async down(knex) {
// Revert the changes made in the "up" function
await knex.schema.table('user', (table) => {
table.string('scope').notNullable().defaultTo('user');
});
}
};

21
lib/migrations/4-user.js Normal file
View File

@ -0,0 +1,21 @@
'use strict';
module.exports = {
async up(knex) {
// Add the "scope" field to the "user" table
await knex.schema.table('user', (table) => {
table.string('scope').notNullable().defaultTo('user');
});
},
async down(knex) {
// Revert the changes made in the "up" function
await knex.schema.table('user', (table) => {
table.dropColumn('scope');
});
}
};

23
lib/models/favorite.js Normal file
View File

@ -0,0 +1,23 @@
'use strict';
const Joi = require('joi');
const { Model } = require('@hapipal/schwifty');
module.exports = class Favorite extends Model {
static get tableName() {
return 'favorites';
}
static get joiSchema() {
return Joi.object({
id: Joi.number().integer().greater(0),
user_id: Joi.number().integer().greater(0).required().example(1).description('User id'),
movie_id: Joi.number().integer().greater(0).required().example(1).description('Movie id')
});
}
}

35
lib/models/movie.js Normal file
View File

@ -0,0 +1,35 @@
'use strict';
const Joi = require('joi');
const { Model } = require('@hapipal/schwifty');
module.exports = class Movie extends Model {
static get tableName() {
return 'movie';
}
static get joiSchema() {
return Joi.object({
id: Joi.number().integer().greater(0),
title: Joi.string().min(3).required().example('The Matrix').description('Title of the film'),
description: Joi.string().min(3).required().example('A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.').description('Description of the film'),
director: Joi.string().min(3).required().example('Lana Wachowski').description('Director of the film'),
releaseDate: Joi.date().required().example('1999-03-31').description('Release date of the film'),
created_at: Joi.date(),
updated_at: Joi.date()
});
}
$beforeInsert(queryContext) {
this.created_at = new Date();
this.created_at = this.updated_at;
}
$beforeUpdate(queryContext) {
this.updated_at = new Date();
}
}

45
lib/models/user.js Normal file
View File

@ -0,0 +1,45 @@
'use strict';
const Joi = require('joi');
const { Model } = require('@hapipal/schwifty');
const { encryptSha1 } = require('iut-encrypt-cemal'); // Importe les fonctions d'encryption
module.exports = class User extends Model {
static get tableName() {
return 'user';
}
static get joiSchema() {
return Joi.object({
id: Joi.number().integer().greater(0),
scope: Joi.string().required().example('user').description('Scope of the user'),
username: Joi.string().min(3).required().example('john_doe').description('Username of the user'),
firstName: Joi.string().min(3).required().example('John').description('Firstname of the user'),
lastName: Joi.string().min(3).required().example('Doe').description('Lastname of the user'),
email: Joi.string().email().required().example('john@example.com').description('Email address of the user'),
password: Joi.string().min(8).required().example('password123').description('Password of the user'),
createdAt: Joi.date(),
updatedAt: Joi.date()
});
}
$beforeInsert(queryContext) {
this.scope = 'user';
this.updatedAt = new Date();
this.createdAt = this.updatedAt;
this.password = encryptSha1(this.password); // Encrypte le mot de passe avant insertion
}
$beforeUpdate(queryContext) {
this.updatedAt = new Date();
// Si le mot de passe a été modifié, ré-encrypte-le avant la mise à jour
if (this.password && this.old && this.password !== this.old.password) {
this.password = encryptSha1(this.password);
}
}
};

7
lib/plugins/@hapi.jwt.js Normal file
View File

@ -0,0 +1,7 @@
'use strict';
module.exports = {
plugins: {
options: {}
}
};

View File

@ -0,0 +1,5 @@
'use strict';
module.exports = {
options: { }
};

114
lib/routes/favorites.js Normal file
View File

@ -0,0 +1,114 @@
'use strict';
const Joi = require('joi');
const Jwt = require('@hapi/jwt');
module.exports = [
{
method: 'POST',
path: '/favorites/add',
options: {
auth: {
scope : ['user', 'admin']
},
tags: ['api'],
validate: {
payload: Joi.object({
movieId: Joi.number().required().example(1).description('Id of the movie'),
})
}
},
handler: async (request, h) => {
const {userService} = request.services();
const { favoriteService } = request.services();
const { movieId } = request.payload;
//Search user id in the database with the email
const userId = await userService.getByEmail(request.auth.credentials.email).then((user) => user.id)
//If movie not exist, return error
const { Movie } = request.models();
const movie = await Movie.query().findById(movieId);
if(!movie) {
return h.response({message: 'Movie not found'}).code(400);
}
//if movie already in favorite, return error
const favorite = await favoriteService.getByMovieAndUser(movieId, userId);
if(favorite) {
return h.response({message: 'Movie already in favorite'}).code(400);
}
// Appelle la méthode create du favoriteService en passant les champs nécessaires
return await favoriteService.create({
movie_id: movieId,
user_id: userId
});
}
},
{
method: 'GET',
path: '/favorites',
options: {
auth: {
scope : ['user', 'admin']
},
tags: ['api']
},
handler: async (request, h) => {
const { Favorite } = request.models();
const { favoriteService } = request.services();
// Appelle la méthode list du favoriteService pour récupérer tous les favoris
return await favoriteService.list();
}
},
{
method: 'DELETE',
path: '/favorites/remove',
options: {
auth: {
scope : ['user', 'admin']
},
tags: ['api'],
validate: {
payload: Joi.object({
movieId: Joi.number().required().example(1).description('Id of the movie'),
})
}
},
handler: async (request, h) => {
const { userService } = request.services();
const {favoriteService} = request.services();
const {movieId} = request.payload;
const userId = await userService.getByEmail(request.auth.credentials.email).then((user) => user.id)
//If movie not exist, return error
const { Movie } = request.models();
const movie = await Movie.query().findById(movieId);
if(!movie) {
return h.response({message: 'Movie not found'}).code(400);
}
// If the movie is not in the favorite, return an error
const favorite = await favoriteService.getByMovieAndUser(movieId, userId);
if(!favorite) {
return h.response({message: 'Movie not in favorite'}).code(400);
}
// Appelle la méthode remove du favoriteService pour supprimer le favori
return await favoriteService.delete({
movie_id: movieId,
user_id: userId
});
}
}
]

382
lib/routes/movie.js Normal file
View File

@ -0,0 +1,382 @@
'use strict';
const Joi = require('joi');
const Jwt = require('@hapi/jwt');
module.exports = [
{
method: 'POST',
path: '/movie',
options: {
auth: {
scope : 'admin'
},
tags: ['api'],
validate: {
payload: Joi.object({
title: Joi.string().required().min(3).example('The Matrix').description('Title of the movie'),
description: Joi.string().required().min(3).example('A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.').description('Description of the movie'),
director: Joi.string().required().min(3).example('Lana Wachowski').description('Director of the movie'),
releaseDate: Joi.date().required().example('1999-03-31').description('Release date of the movie'),
})
}
},
handler: async (request, h) => {
const { User } = request.models();
const { movieService } = request.services();
const { title, description, director, releaseDate } = request.payload;
//send email to all users
const { emailService } = request.services();
const users = await User.query();
for (const user of users) {
await emailService.sendEmail(
user.email,
user.firstName,
user.lastName,
'New movie added',
'<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <title>A new movie was added !</title>\n' +
' <style>\n' +
' body {\n' +
' font-family: Arial, sans-serif;\n' +
' background-color: #f7f7f7;\n' +
' margin: 0;\n' +
' padding: 0;\n' +
' color: #333;\n' +
' }\n' +
'\n' +
' .container {\n' +
' max-width: 600px;\n' +
' margin: 50px auto;\n' +
' padding: 20px;\n' +
' background-color: #fff;\n' +
' border-radius: 10px;\n' +
' box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .header {\n' +
' text-align: center;\n' +
' margin-bottom: 30px;\n' +
' }\n' +
'\n' +
' .logo {\n' +
' width: 100px;\n' +
' height: auto;\n' +
' }\n' +
'\n' +
' .content {\n' +
' text-align: justify;\n' +
' line-height: 1.6;\n' +
' margin-bottom: 30px;\n' +
' font-size: 16px;\n' +
' }\n' +
'\n' +
' .cta-button {\n' +
' display: inline-block;\n' +
' padding: 10px 20px;\n' +
' background-color: #ff6f61;\n' +
' color: #fff;\n' +
' text-decoration: none;\n' +
' border-radius: 5px;\n' +
' margin-top: 30px;\n' +
' transition: background-color 0.3s ease;\n' +
' font-weight: bold;\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .footer {\n' +
' text-align: center;\n' +
' margin-top: 30px;\n' +
' font-size: 12px;\n' +
' color: #666;\n' +
' }\n' +
' </style>\n' +
'</head>\n' +
'\n' +
'<body>\n' +
'<div class="container">\n' +
' <div class="header">\n' +
' <h1>A new movie was added !</h1>\n' +
' </div>\n' +
' <div class="content">\n' +
' <p>Hello,</p>\n' +
' <p>A new movie was just added to the library.</p>\n' +
' <p>Go discover it now !</p>\n' +
' <a href="http://localhost:4000/documentation#/movies/getMovies" class="cta-button">Discover new movie</a>\n' +
' <p>Happy exploring!</p>\n' +
' </div>\n' +
' <div class="footer">\n' +
' <p>&copy; 2024 Cemal. All rights reserved.</p>\n' +
' </div>\n' +
'</div>\n' +
'</body>\n' +
'\n' +
'</html>\n'
);
}
// Appelle la méthode create du movieService en passant les champs nécessaires
return await movieService.create({
title: title,
description: description,
director: director,
releaseDate: releaseDate
});
}
},
{
method: 'GET',
path: '/movies',
options: {
tags: ['api'],
auth: false
},
handler: async (request, h) => {
const { Movie } = request.models();
const { movieService } = request.services();
// Appelle la méthode list du movieService pour récupérer tous les films
return await movieService.list();
}
},
{
method: 'GET',
path: '/movie/{id}',
options: {
tags: ['api'],
auth: false,
validate: {
params: Joi.object({
id: Joi.number().integer().required().example(1).description('ID of the movie')
})
}
},
handler: async (request, h) => {
const { Movie } = request.models();
const { movieService } = request.services();
const { id } = request.params;
// Appelle la méthode get du movieService pour récupérer le film par son ID
return await movieService.get(id);
}
},
{
method: 'DELETE',
path: '/movie/{id}',
options: {
auth: {
scope : 'admin'
},
tags: ['api'],
validate: {
params: Joi.object({
id: Joi.number().integer().positive().required().example(1).description('ID of the movie to delete')
})
}
},
handler: async (request, h) => {
const { movieService } = request.services();
const { id } = request.params;
// Appelle la méthode delete du movieService pour supprimer le film par son ID
await movieService.delete(id);
// Renvoie une réponse vide lorsque la suppression se déroule correctement
return 'deleted';
}
},
{
method: 'PATCH',
path: '/movie/{id}',
options: {
auth: {
scope : 'admin'
},
tags: ['api'],
validate: {
params: Joi.object({
id: Joi.number().integer().positive().required().example(1).description('ID of the movie to update')
}),
payload: Joi.object({
title: Joi.string().min(3).example('The Matrix').description('Title of the movie'),
description: Joi.string().min(3).example('A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.').description('Description of the movie'),
director: Joi.string().min(3).example('Lana Wachowski').description('Director of the movie'),
releaseDate: Joi.date().example('1999-03-31').description('Release date of the movie'),
})
}
},
handler: async (request, h) => {
const { movieService } = request.services();
const { id } = request.params;
//Email users who have favorited the movie
const { emailService } = request.services();
const { Favorite } = request.models();
const { User } = request.models();
const favorites = await Favorite.query().where('movie_id', id);
for (const favorite of favorites) {
const user = await User.query().findById(favorite.user_id);
await emailService.sendEmail(
user.email,
user.firstName,
user.lastName,
'Movie updated',
'<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <title>A movie was updated !</title>\n' +
' <style>\n' +
' body {\n' +
' font-family: Arial, sans-serif;\n' +
' background-color: #f7f7f7;\n' +
' margin: 0;\n' +
' padding: 0;\n' +
' color: #333;\n' +
' }\n' +
'\n' +
' .container {\n' +
' max-width: 600px;\n' +
' margin: 50px auto;\n' +
' padding: 20px;\n' +
' background-color: #fff;\n' +
' border-radius: 10px;\n' +
' box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .header {\n' +
' text-align: center;\n' +
' margin-bottom: 30px;\n' +
' }\n' +
'\n' +
' .logo {\n' +
' width: 100px;\n' +
' height: auto;\n' +
' }\n' +
'\n' +
' .content {\n' +
' text-align: justify;\n' +
' line-height: 1.6;\n' +
' margin-bottom: 30px;\n' +
' font-size: 16px;\n' +
' }\n' +
'\n' +
' .cta-button {\n' +
' display: inline-block;\n' +
' padding: 10px 20px;\n' +
' background-color: #ff6f61;\n' +
' color: #fff;\n' +
' text-decoration: none;\n' +
' border-radius: 5px;\n' +
' margin-top: 30px;\n' +
' transition: background-color 0.3s ease;\n' +
' font-weight: bold;\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .footer {\n' +
' text-align: center;\n' +
' margin-top: 30px;\n' +
' font-size: 12px;\n' +
' color: #666;\n' +
' }\n' +
' </style>\n' +
'</head>\n' +
'\n' +
'<body>\n' +
'<div class="container">\n' +
' <div class="header">\n' +
' <h1>A movie was updated !</h1>\n' +
' </div>\n' +
' <div class="content">\n' +
' <p>Hello,</p>\n' +
' <p>The movie ' + request.payload.title + ' was just updated in the library.</p>\n' +
' <p>Go check it out now !</p>\n' +
' <a href="http://localhost:4000/documentation#/movie/getMovieId" class="cta-button">Discover updated movie</a>\n' +
' <p>Happy exploring!</p>\n' +
' </div>\n' +
' <div class="footer">\n' +
' <p>&copy; 2024 Cemal. All rights reserved.</p>\n' +
' </div>\n' +
'</div>\n' +
'</body>\n' +
'\n' +
'</html>\n'
);
}
// Appelle la méthode update du movieService pour mettre à jour le film par son ID
return await movieService.update(id, request.payload);
}
},
{
method: 'GET',
path: '/movie/csv',
options: {
auth: {
scope: 'admin'
},
tags: ['api']
},
handler: async (request, h) => {
const { rabbitmqService } = request.services();
const { Movie } = request.models();
const { movieService } = request.services();
try {
// Récupérer les films depuis la base de données
const movies = await Movie.query();
// Générer le fichier CSV
const csvData = await movieService.generateCsvData(movies);
console.log(csvData);
// Envoyer le fichier CSV via RabbitMQ pour l'envoi par e-mail
await rabbitmqService.sendCsvToQueue();
//When message is received, send the csv to the admin email
await rabbitmqService.receiveAndReturnCSV().then(
//Send the csv to the admin email
async () => {
const {emailService} = request.services();
await emailService.sendEmailWithAttachment(
request.auth.credentials.email,
'Admin',
'Admin',
'Movie list in CSV',
'Find the movie list in CSV format attached to this email.',
csvData
);
});
return h.response({ message: 'CSV sent to the admin email' }).code(200);
} catch (error) {
console.error('Erreur lors de l\'export CSV :', error);
return h.response({ message: 'Erreur lors du traitement de la requête' + error }).code(500);
}
}
}
]

View File

@ -1,13 +1,257 @@
'use strict';
module.exports = {
method: 'get',
const Joi = require('joi');
const { encryptSha1, compareSha1 } = require('iut-encrypt-cemal'); // Importe les fonctions d'encryption
const Jwt = require('@hapi/jwt');
module.exports = [
{
method: 'post',
path: '/user',
options: {
auth: false,
tags:['api'],
validate: {
payload: Joi.object({
scope: Joi.string().valid('admin', 'user').example('admin').description('Scope of the user (user or admin)'),
firstName: Joi.string().required().min(3).example('John').description('Firstname of the user'),
lastName: Joi.string().required().min(3).example('Doe').description('Lastname of the user'),
username: Joi.string().required().min(3).example('john_doe').description('Username of the user'),
email: Joi.string().email().required().example('john@example.com').description('Email address of the user'),
password: Joi.string().required().min(8).example('password123').description('Password of the user')
})
}
},
handler: async (request, h) => {
const { userService } = request.services();
const { emailService } = request.services();
//send welcome email
const { email, firstName, lastName } = request.payload;
await emailService.sendEmail(
email,
firstName,
lastName,
'welcome',
'<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <title>Welcome to Our Application!</title>\n' +
' <style>\n' +
' body {\n' +
' font-family: Arial, sans-serif;\n' +
' background-color: #f7f7f7;\n' +
' margin: 0;\n' +
' padding: 0;\n' +
' color: #333;\n' +
' }\n' +
'\n' +
' .container {\n' +
' max-width: 600px;\n' +
' margin: 50px auto;\n' +
' padding: 20px;\n' +
' background-color: #fff;\n' +
' border-radius: 10px;\n' +
' box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .header {\n' +
' text-align: center;\n' +
' margin-bottom: 30px;\n' +
' }\n' +
'\n' +
' .logo {\n' +
' width: 100px;\n' +
' height: auto;\n' +
' }\n' +
'\n' +
' .content {\n' +
' text-align: justify;\n' +
' line-height: 1.6;\n' +
' margin-bottom: 30px;\n' +
' font-size: 16px;\n' +
' }\n' +
'\n' +
' .cta-button {\n' +
' display: inline-block;\n' +
' padding: 10px 20px;\n' +
' background-color: #ff6f61;\n' +
' color: #fff;\n' +
' text-decoration: none;\n' +
' border-radius: 5px;\n' +
' margin-top: 30px;\n' +
' transition: background-color 0.3s ease;\n' +
' font-weight: bold;\n' +
' text-align: center;\n' +
' }\n' +
'\n' +
' .footer {\n' +
' text-align: center;\n' +
' margin-top: 30px;\n' +
' font-size: 12px;\n' +
' color: #666;\n' +
' }\n' +
' </style>\n' +
'</head>\n' +
'\n' +
'<body>\n' +
'<div class="container">\n' +
' <div class="header">\n' +
' <h1>Welcome to Our Application!</h1>\n' +
' </div>\n' +
' <div class="content">\n' +
' <p>Hello,</p>\n' +
' <p>We are thrilled to have you join our community! Your journey with us begins now, and we can\'t wait to\n' +
' share\n' +
' all the exciting features and updates we have in store for you.</p>\n' +
' <p>To get started, simply log in to your account and explore everything our application has to offer.\n' +
' Don\'t hesitate to reach out to our support team if you have any questions or need assistance along the\n' +
' way.</p>\n' +
' <a href="http://localhost:4000/documentation#/user/postUser" class="cta-button">Log In Now</a>\n' +
' <p>Happy exploring!</p>\n' +
' </div>\n' +
' <div class="footer">\n' +
' <p>&copy; 2024 Cemal. All rights reserved.</p>\n' +
' </div>\n' +
'</div>\n' +
'</body>\n' +
'\n' +
'</html>\n'
);
// Appelle la méthode create du userService en passant les champs nécessaires
return await userService.create({
scope: request.payload.scope,
firstName: request.payload.firstName,
lastName: request.payload.lastName,
username: request.payload.username,
email: request.payload.email,
password: request.payload.password
});
}
},
{
method: 'GET',
path: '/users',
options: {
tags: ['api'],
},
handler: async (request, h) => {
const { User } = request.models();
return { firstName: 'John', lastName: 'Doe'};
// Récupère tous les utilisateurs dans la base de données
const users = await User.query();
return users; // Renvoie tous les utilisateurs
}
};
},
{
method: 'DELETE',
path: '/user/{id}',
options: {
auth: {
scope : 'admin'
},
tags: ['api'],
validate: {
params: Joi.object({
id: Joi.number().integer().positive().required().example(1).description('ID of the user to delete')
})
}
},
handler: async (request, h) => {
const { userService } = request.services();
const { id } = request.params;
// Appelle la méthode delete du userService pour supprimer l'utilisateur par son ID
await userService.delete(id);
// Renvoie une réponse vide lorsque la suppression se déroule correctement
return 'deleted';
}
},
{
method: 'PATCH',
path: '/user/{id}',
options: {
auth: {
strategy: 'jwt',
scope : ['admin']
},
tags: ['api'],
validate: {
params: Joi.object({
id: Joi.number().integer().positive().required().example(1).description('ID of the user to update')
}),
payload: Joi.object({
scope: Joi.string().valid('admin').example('admin').description('New scope of the user'),
username: Joi.string().min(3).example('john_doe').description('New username of the user'),
firstName: Joi.string().min(3).example('John').description('New firstname of the user'),
lastName: Joi.string().min(3).example('Doe').description('New lastname of the user'),
email: Joi.string().email().example('john@example.com').description('New email address of the user'),
password: Joi.string().min(8).example('password123').description('New password of the user')
})
}
},
handler: async (request, h) => {
const { userService } = request.services();
const { id } = request.params;
// Appelle la méthode update du userService pour mettre à jour l'utilisateur par son ID
return await userService.update(id, request.payload);
}
},
{
method: 'POST',
path: '/user/login',
options: {
auth: false,
tags: ['api'],
validate: {
payload: Joi.object({
email: Joi.string().email().required().example('john@example.com').description('Email address of the user'),
password: Joi.string().min(8).required().example('password123').description('Password of the user')
})
}
},
handler: async (request, h) => {
const {User} = request.models();
const {email, password} = request.payload;
// Récupère l'utilisateur par son email depuis la base de données
const user = await User.query().findOne({email});
// Vérifie si l'utilisateur existe et si le mot de passe est valide
if (user && compareSha1(password, user.password)) {
// Génère un JWT avec les informations de l'utilisateur
const token = Jwt.token.generate({
aud: 'urn:audience:iut',
iss: 'urn:issuer:iut',
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
scope: user.scope,
}, {
key: 'random_string', // Clé secrète pour signer le JWT (devrait être stockée en toute sécurité)
algorithm: 'HS512'
}, {
ttlSec: 14400 // Durée de validité du JWT en secondes (4 heures)
});
// Retourne le JWT généré
return {token};
} else {
// Si le mot de passe n'est pas correct, retourne une réponse 401 Unauthorized
return h.response().code(401);
}
},
}
];

74
lib/services/email.js Normal file
View File

@ -0,0 +1,74 @@
const nodemailer = require('nodemailer');
const {Service} = require("@hapipal/schmervice");
// Fonction pour créer un transporteur SMTP réutilisable
module.exports = class EmailService extends Service {
createTransporter() {
// Crée un transporteur SMTP réutilisable
return nodemailer.createTransport({
host: 'smtp.ethereal.email',
port: 587,
auth: {
user: 'adeline.ondricka5@ethereal.email',
pass: 'B4khRtXZPNqtr58bAu'
}
});
}
// Fonction pour envoyer un e-mail
async sendEmail(email, firstName, lastName, subject, html) {
// Crée un transporteur SMTP réutilisable
const transporter = this.createTransporter();
// Paramètres de l'e-mail
const mailOptions = {
from: process.env.EMAIL_FROM,
to: email,
subject: subject,
html: html
};
// Envoyer l'e-mail
try {
const info = await transporter.sendMail(mailOptions);
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info)); // For testing with Ethereal
return info;
} catch (error) {
console.error('Error sending email:', error);
throw error; // Propagate the error
}
}
async sendEmailWithAttachment(email, firstName, lastName, subject, html, attachment) {
// Crée un transporteur SMTP réutilisable
const transporter = this.createTransporter();
// Paramètres de l'e-mail
const mailOptions = {
from: process.env.EMAIL_FROM,
to: email,
subject: subject,
html: html,
attachments: [
{
filename: 'movies.csv',
content: attachment
}
]
};
// Envoyer l'e-mail
try {
const info = await transporter.sendMail(mailOptions);
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info)); // For testing with Ethereal
return info;
} catch (error) {
console.error('Error sending email:', error);
throw error; // Propagate the error
}
}
}

37
lib/services/favorite.js Normal file
View File

@ -0,0 +1,37 @@
'use strict';
const { Service } = require('@hapipal/schmervice');
module.exports = class FavoriteService extends Service {
async list() {
const { Favorite } = this.server.models();
return Favorite.query();
}
async create(payload) {
const { Favorite } = this.server.models();
return Favorite.query().insert(payload);
}
async get(id) {
const { Favorite } = this.server.models();
return Favorite.query().findById(id);
}
async update(id, payload) {
const { Favorite } = this.server.models();
return Favorite.query().patchAndFetchById(id, payload);
}
async delete(payload) {
const { Favorite } = this.server.models();
return Favorite.query().delete().where(payload);
}
async getByMovieAndUser(movieId, userId) {
const { Favorite } = this.server.models();
return Favorite.query().findOne({movie_id: movieId, user_id: userId});
}
}

BIN
lib/services/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

48
lib/services/movie.js Normal file
View File

@ -0,0 +1,48 @@
'use strict';
const { Service } = require('@hapipal/schmervice');
const { parse } = require('json2csv');
module.exports = class MovieService extends Service {
async list() {
const { Movie } = this.server.models();
return Movie.query();
}
async create(payload) {
const { Movie } = this.server.models();
return Movie.query().insert(payload);
}
async get(id) {
const { Movie } = this.server.models();
return Movie.query().findById(id);
}
async update(id, payload) {
const { Movie } = this.server.models();
return Movie.query().patchAndFetchById(id, payload);
}
async delete(id) {
const { Movie } = this.server.models();
return Movie.query().deleteById(id);
}
async generateCsvData(movies) {
try {
// Définir les champs CSV à partir des propriétés des films
const fields = ['title', 'description', 'director', 'releaseDate'];
console.log(parse(movies, {fields}));
// Convertir la liste des films en données CSV
return parse(movies, {fields});
} catch (error) {
console.error('Erreur lors de la génération des données CSV :', error);
throw error;
}
}
}

50
lib/services/rabbitmq.js Normal file
View File

@ -0,0 +1,50 @@
'use strict';
const amqp = require('amqplib');
const {Service} = require("@hapipal/schmervice");
module.exports = class RabbitmqService extends Service {
async sendCsvToQueue() {
try {
const connection = await amqp.connect('amqp://localhost'); // Assurez-vous d'ajuster l'URL de connexion si nécessaire
const channel = await connection.createChannel();
const queue = 'csv_queue';
await channel.assertQueue(queue, { durable: false });
await channel.sendToQueue(queue, Buffer.from('Send the CSV PLZ!'));
await channel.close();
await connection.close();
} catch (error) {
console.error('Erreur lors de l\'envoi du CSV à la file d\'attente RabbitMQ :', error);
throw error;
}
}
async receiveAndReturnCSV() {
try {
const connection = await amqp.connect('amqp://localhost'); // Assurez-vous d'ajuster l'URL de connexion si nécessaire
const channel = await connection.createChannel();
const queue = 'csv_queue';
await channel.assertQueue(queue, { durable: false });
console.log('En attente de messages dans la file d\'attente RabbitMQ...');
//when message is received, send the csv to the admin email
await channel.consume(queue, async (message) => {
return message.content.toString();
});
await channel.close();
await connection.close();
} catch (error) {
console.error('Erreur lors de la réception du CSV de la file d\'attente RabbitMQ :', error);
throw error;
}
}
};

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Welcome to Our Application!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f7f7f7;
margin: 0;
padding: 0;
color: #333;
}
.container {
max-width: 600px;
margin: 50px auto;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
width: 100px;
height: auto;
}
.content {
text-align: justify;
}
.cta-button {
display: inline-block;
padding: 10px 20px;
background-color: #ff6f61;
color: #fff;
text-decoration: none;
border-radius: 5px;
margin-top: 30px;
}
.footer {
text-align: center;
margin-top: 30px;
font-size: 12px;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<img src="../logo.png" alt="Logo" class="logo">
<h1>Welcome to Our Application!</h1>
</div>
<div class="content">
<p>Hello,</p>
<p>We are thrilled to have you join our community! Your journey with us begins now, and we can't wait to
share
all the exciting features and updates we have in store for you.</p>
<p>To get started, simply log in to your account and explore everything our application has to offer.
Don't hesitate to reach out to our support team if you have any questions or need assistance along the
way.</p>
<a href="http://localhost:4000/documentation#/user/postUser" class="cta-button">Log In Now</a>
<p>Happy exploring!</p>
</div>
<div class="footer">
<p>&copy; 2024 Cemal. All rights reserved.</p>
</div>
</div>
</body>
</html>

68
lib/services/user.js Normal file
View File

@ -0,0 +1,68 @@
'use strict';
const { Service } = require('@hapipal/schmervice');
const { encryptSha1, compareSha1 } = require('iut-encrypt-cemal'); // Importe les fonctions d'encryption
module.exports = class UserService extends Service {
create(user){
const { User } = this.server.models();
return User.query().insertAndFetch(user);
}
async update(id, userData) {
const { User } = this.server.models();
// Récupère l'utilisateur à mettre à jour
let user = await User.query().findById(id);
if (!user) {
throw new Error(`User with ID ${id} not found.`);
}
// Extrait les champs nécessaires de userData
const { firstName, lastName, username, email, password } = userData;
// Met à jour les champs de l'utilisateur avec les nouvelles valeurs
user = {
...user,
firstName,
lastName,
username,
email,
password: password ? encryptSha1(password) : user.password // Si un nouveau mot de passe est fourni, encrypte-le
};
// Effectue la mise à jour de l'utilisateur dans la base de données
return await User.query().patchAndFetchById(id, user);
}
// Méthode pour supprimer un utilisateur
async delete(id) {
const { User } = this.server.models();
// Récupère l'utilisateur à supprimer
const user = await User.query().findById(id);
if (!user) {
throw new Error(`User with ID ${id} not found.`);
}
// Supprime l'utilisateur de la base de données
return await User.query().deleteById(id);
}
// Méthode pour récupérer un utilisateur par son email
async getByEmail(email) {
const {User} = this.server.models();
const user = await User.query().findOne({email});
return user;
}
}

585
package-lock.json generated
View File

@ -1,17 +1,24 @@
{
"name": "hapipal-boilerplate",
"name": "iut-encrypt-cemal",
"version": "3.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "hapipal-boilerplate",
"name": "iut-encrypt-cemal",
"version": "3.0.0",
"dependencies": {
"@hapi/boom": "9.x.x",
"@hapi/jwt": "^3.2.0",
"@hapipal/haute-couture": "4.x.x",
"@hapipal/schmervice": "^3.0.0",
"@hapipal/schwifty": "6.x.x",
"amqplib": "^0.10.3",
"iut-encrypt-cemal": "^1.0.0",
"joi": "17.x.x",
"json2csv": "^6.0.0-alpha.2",
"mysql": "^2.18.1",
"nodemailer": "^6.9.8",
"objection": "2.x.x"
},
"devDependencies": {
@ -21,7 +28,9 @@
"@hapi/glue": "8.x.x",
"@hapi/hapi": "20.x.x",
"@hapi/hoek": "9.x.x",
"@hapi/inert": "6.x.x",
"@hapi/lab": "24.x.x",
"@hapi/vision": "6.x.x",
"@hapipal/confidence": "6.x.x",
"@hapipal/hpal": "3.x.x",
"@hapipal/hpal-debug": "2.x.x",
@ -30,6 +39,7 @@
"dotenv": "8.x.x",
"eslint": "7.x.x",
"exiting": "6.x.x",
"hapi-swagger": "14.x.x",
"knex": "0.21.x",
"sqlite3": "5.x.x"
},
@ -46,6 +56,19 @@
"node": ">=0.10.0"
}
},
"node_modules/@acuminous/bitsyntax": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz",
"integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==",
"dependencies": {
"buffer-more-ints": "~1.0.0",
"debug": "^4.3.4",
"safe-buffer": "~5.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
@ -59,6 +82,68 @@
"node": ">=6.0.0"
}
},
"node_modules/@apidevtools/json-schema-ref-parser": {
"version": "9.1.2",
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
"integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
"dev": true,
"dependencies": {
"@jsdevtools/ono": "^7.1.3",
"@types/json-schema": "^7.0.6",
"call-me-maybe": "^1.0.1",
"js-yaml": "^4.1.0"
}
},
"node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@apidevtools/openapi-schemas": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/@apidevtools/swagger-methods": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
"dev": true
},
"node_modules/@apidevtools/swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
"dev": true,
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@apidevtools/openapi-schemas": "^2.0.4",
"@apidevtools/swagger-methods": "^3.0.2",
"@jsdevtools/ono": "^7.1.3",
"call-me-maybe": "^1.0.1",
"z-schema": "^5.0.1"
},
"peerDependencies": {
"openapi-types": ">=7"
}
},
"node_modules/@babel/code-frame": {
"version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
@ -541,6 +626,28 @@
"@hapi/hoek": "9.x.x"
}
},
"node_modules/@hapi/catbox-object": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@hapi/catbox-object/-/catbox-object-3.0.1.tgz",
"integrity": "sha512-3w6E2DXtjWbmLYi4WcFUOor5jgrXN4PWhDrMrXKP/cEsFSfVSRJ0FhY2PXrhrUHwcllfKezYafWU3tQ5+8RO1w==",
"dependencies": {
"@hapi/boom": "^10.0.1",
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/catbox-object/node_modules/@hapi/boom": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.1.tgz",
"integrity": "sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==",
"dependencies": {
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/catbox-object/node_modules/@hapi/hoek": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.4.tgz",
"integrity": "sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ=="
},
"node_modules/@hapi/code": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/@hapi/code/-/code-8.0.7.tgz",
@ -663,6 +770,20 @@
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="
},
"node_modules/@hapi/inert": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/@hapi/inert/-/inert-6.0.5.tgz",
"integrity": "sha512-eVAdUVhJLmmXLM/Zt7u5H5Vzazs9GKe4zfPK2b97ePHEfs3g/AQkxHfYQjJqMy11hvyB7a21Z6rBEA0R//dtXw==",
"dev": true,
"dependencies": {
"@hapi/ammo": "5.x.x",
"@hapi/boom": "9.x.x",
"@hapi/bounce": "2.x.x",
"@hapi/hoek": "9.x.x",
"@hapi/validate": "1.x.x",
"lru-cache": "^6.0.0"
}
},
"node_modules/@hapi/iron": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz",
@ -675,6 +796,99 @@
"@hapi/hoek": "9.x.x"
}
},
"node_modules/@hapi/jwt": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@hapi/jwt/-/jwt-3.2.0.tgz",
"integrity": "sha512-2EU5zdr0petG63J2RHiagGByA1Qr6qzxMmrJJ3/0cm78be1Lq4vi038YgKJvbBSxSboIp5SWGZdYB6+CJlqEoQ==",
"dependencies": {
"@hapi/b64": "^6.0.0",
"@hapi/boom": "^10.0.0",
"@hapi/bounce": "^3.0.0",
"@hapi/bourne": "^3.0.0",
"@hapi/catbox-object": "^3.0.0",
"@hapi/cryptiles": "^6.0.0",
"@hapi/hoek": "^10.0.0",
"@hapi/wreck": "^18.0.0",
"ecdsa-sig-formatter": "^1.0.0",
"joi": "^17.2.1"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/b64": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-6.0.1.tgz",
"integrity": "sha512-ZvjX4JQReUmBheeCq+S9YavcnMMHWqx3S0jHNXWIM1kQDxB9cyfSycpVvjfrKcIS8Mh5N3hmu/YKo4Iag9g2Kw==",
"dependencies": {
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/b64/node_modules/@hapi/hoek": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.4.tgz",
"integrity": "sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ=="
},
"node_modules/@hapi/jwt/node_modules/@hapi/boom": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.1.tgz",
"integrity": "sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==",
"dependencies": {
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/boom/node_modules/@hapi/hoek": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.4.tgz",
"integrity": "sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ=="
},
"node_modules/@hapi/jwt/node_modules/@hapi/bounce": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-3.0.1.tgz",
"integrity": "sha512-G+/Pp9c1Ha4FDP+3Sy/Xwg2O4Ahaw3lIZFSX+BL4uWi64CmiETuZPxhKDUD4xBMOUZbBlzvO8HjiK8ePnhBadA==",
"dependencies": {
"@hapi/boom": "^10.0.1",
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/bounce/node_modules/@hapi/hoek": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.4.tgz",
"integrity": "sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ=="
},
"node_modules/@hapi/jwt/node_modules/@hapi/bourne": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-3.0.0.tgz",
"integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w=="
},
"node_modules/@hapi/jwt/node_modules/@hapi/cryptiles": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-6.0.1.tgz",
"integrity": "sha512-9GM9ECEHfR8lk5ASOKG4+4ZsEzFqLfhiryIJ2ISePVB92OHLp/yne4m+zn7z9dgvM98TLpiFebjDFQ0UHcqxXQ==",
"dependencies": {
"@hapi/boom": "^10.0.1"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/hoek": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-10.0.1.tgz",
"integrity": "sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw=="
},
"node_modules/@hapi/jwt/node_modules/@hapi/wreck": {
"version": "18.0.1",
"resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-18.0.1.tgz",
"integrity": "sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg==",
"dependencies": {
"@hapi/boom": "^10.0.1",
"@hapi/bourne": "^3.0.0",
"@hapi/hoek": "^11.0.2"
}
},
"node_modules/@hapi/jwt/node_modules/@hapi/wreck/node_modules/@hapi/hoek": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.4.tgz",
"integrity": "sha512-PnsP5d4q7289pS2T2EgGz147BFJ2Jpb4yrEdkpz2IhgEUzos1S7HTl7ezWh1yfYzYlj89KzLdCRkqsP6SIryeQ=="
},
"node_modules/@hapi/lab": {
"version": "24.7.1",
"resolved": "https://registry.npmjs.org/@hapi/lab/-/lab-24.7.1.tgz",
@ -861,8 +1075,7 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@hapi/vision/-/vision-6.1.0.tgz",
"integrity": "sha512-ll0zJ13xDxCYIWvC1aq/8srK0bTXfqZYGT+YoTi/fS42gYYJ3dnvmS35r8T8XXtJ6F6cmya8G2cRlMR/z11LQw==",
"optional": true,
"peer": true,
"devOptional": true,
"dependencies": {
"@hapi/boom": "9.x.x",
"@hapi/bounce": "2.x.x",
@ -995,6 +1208,17 @@
}
}
},
"node_modules/@hapipal/schmervice": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@hapipal/schmervice/-/schmervice-3.0.0.tgz",
"integrity": "sha512-1v7GY6BPHP9vLrUkQ1mi8qnzrAKKLy0J0rRznhogkILcvuwZXMHuMuSBrmmyEmHh4fPvL+WxPgeINjrL0TRtxQ==",
"engines": {
"node": ">=16"
},
"peerDependencies": {
"@hapi/hapi": ">=20 <22"
}
},
"node_modules/@hapipal/schwifty": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@hapipal/schwifty/-/schwifty-6.2.0.tgz",
@ -1101,6 +1325,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@jsdevtools/ono": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
"dev": true
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@ -1163,6 +1393,17 @@
"resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
},
"node_modules/@streamparser/json": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.6.tgz",
"integrity": "sha512-vL9EVn/v+OhZ+Wcs6O4iKE9EUpwHUqHmCtNUMWjqp+6dr85+XPOSGTEsqYNq1Vn04uk9SWlOVmx9J48ggJVT2Q=="
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -1205,6 +1446,41 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/amqplib": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
"integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
"dependencies": {
"@acuminous/bitsyntax": "^0.1.2",
"buffer-more-ints": "~1.0.0",
"readable-stream": "1.x >=1.1.9",
"url-parse": "~1.5.10"
},
"engines": {
"node": ">=10"
}
},
"node_modules/amqplib/node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ=="
},
"node_modules/amqplib/node_modules/readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"node_modules/amqplib/node_modules/string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
"node_modules/ansi-colors": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
@ -1508,6 +1784,14 @@
"tweetnacl": "^0.14.3"
}
},
"node_modules/bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
"engines": {
"node": "*"
}
},
"node_modules/bin-v8-flags-filter": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
@ -1587,6 +1871,11 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"node_modules/buffer-more-ints": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz",
"integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg=="
},
"node_modules/cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -1606,6 +1895,12 @@
"node": ">=0.10.0"
}
},
"node_modules/call-me-maybe": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
"dev": true
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@ -1680,6 +1975,14 @@
"node": ">=4"
}
},
"node_modules/charenc": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
"engines": {
"node": "*"
}
},
"node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
@ -1801,6 +2104,16 @@
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
"dev": true,
"optional": true,
"engines": {
"node": "^12.20.0 || >=14"
}
},
"node_modules/component-emitter": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
@ -1838,8 +2151,7 @@
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"devOptional": true
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/cross-spawn": {
"version": "7.0.3",
@ -1855,6 +2167,14 @@
"node": ">= 8"
}
},
"node_modules/crypt": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
"integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
"engines": {
"node": "*"
}
},
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@ -1877,7 +2197,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
@ -2026,6 +2345,14 @@
"safer-buffer": "^2.1.0"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/electron-to-chromium": {
"version": "1.4.647",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.647.tgz",
@ -2826,6 +3153,12 @@
"node": ">= 0.12"
}
},
"node_modules/format-util": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz",
"integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==",
"dev": true
},
"node_modules/fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@ -3149,6 +3482,28 @@
"node": ">=0.10.0"
}
},
"node_modules/hapi-swagger": {
"version": "14.5.5",
"resolved": "https://registry.npmjs.org/hapi-swagger/-/hapi-swagger-14.5.5.tgz",
"integrity": "sha512-qhqmr48+CZrhHDwhg0bHuQ3EW1VWnP71fG8gg5FPAEjF5iIHxIVtRZvioN3dPcBEuk/EqiLoPj/x3va51TbEEA==",
"dev": true,
"dependencies": {
"@hapi/boom": "^9.1.4",
"@hapi/hoek": "^9.3.0",
"handlebars": "^4.7.7",
"http-status": "^1.5.2",
"json-schema-ref-parser": "^6.1.0",
"swagger-parser": "^10.0.3",
"swagger-ui-dist": "^4.11.1"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"@hapi/hapi": "^20.2.2",
"joi": "17.x"
}
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -3297,6 +3652,15 @@
"npm": ">=1.3.7"
}
},
"node_modules/http-status": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-status/-/http-status-1.7.3.tgz",
"integrity": "sha512-GS8tL1qHT2nBCMJDYMHGkkkKQLNkIAHz37vgO68XKvzv+XyqB4oh/DfmMHdtRzfqSJPj1xKG2TaELZtlCz6BEQ==",
"dev": true,
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -3377,8 +3741,7 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"devOptional": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/ini": {
"version": "1.3.8",
@ -3573,6 +3936,14 @@
"dev": true,
"optional": true
},
"node_modules/iut-encrypt-cemal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/iut-encrypt-cemal/-/iut-encrypt-cemal-1.0.0.tgz",
"integrity": "sha512-f+BjMCIRGDLfKRFofgD3OIm7gbwowNp/clvzb9ohEBcYWjjp86wvW5PgVEe34GHrQlVRHSu0qxHZxjFSR9V+EA==",
"dependencies": {
"sha1": "^1.1.1"
}
},
"node_modules/joi": {
"version": "17.12.0",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.12.0.tgz",
@ -3636,6 +4007,18 @@
"dev": true,
"optional": true
},
"node_modules/json-schema-ref-parser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz",
"integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==",
"deprecated": "Please switch to @apidevtools/json-schema-ref-parser",
"dev": true,
"dependencies": {
"call-me-maybe": "^1.0.1",
"js-yaml": "^3.12.1",
"ono": "^4.0.11"
}
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@ -3654,6 +4037,31 @@
"dev": true,
"optional": true
},
"node_modules/json2csv": {
"version": "6.0.0-alpha.2",
"resolved": "https://registry.npmjs.org/json2csv/-/json2csv-6.0.0-alpha.2.tgz",
"integrity": "sha512-nJ3oP6QxN8z69IT1HmrJdfVxhU1kLTBVgMfRnNZc37YEY+jZ4nU27rBGxT4vaqM/KUCavLRhntmTuBFqZLBUcA==",
"dependencies": {
"@streamparser/json": "^0.0.6",
"commander": "^6.2.0",
"lodash.get": "^4.4.2"
},
"bin": {
"json2csv": "bin/json2csv.js"
},
"engines": {
"node": ">= 12",
"npm": ">= 6.13.0"
}
},
"node_modules/json2csv/node_modules/commander": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
"engines": {
"node": ">= 6"
}
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@ -3820,6 +4228,17 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
"dev": true
},
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -4092,6 +4511,34 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/mysql": {
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
"dependencies": {
"bignumber.js": "9.0.0",
"readable-stream": "2.3.7",
"safe-buffer": "5.1.2",
"sqlstring": "2.3.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mysql/node_modules/readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@ -4360,6 +4807,14 @@
"integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
"dev": true
},
"node_modules/nodemailer": {
"version": "6.9.8",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.8.tgz",
"integrity": "sha512-cfrYUk16e67Ks051i4CntM9kshRYei1/o/Gi8K1d+R34OIs21xdFnW7Pt7EucmVKA0LKtqUGNcjMZ7ehjl49mQ==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
@ -4546,6 +5001,22 @@
"wrappy": "1"
}
},
"node_modules/ono": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz",
"integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==",
"dev": true,
"dependencies": {
"format-util": "^1.0.3"
}
},
"node_modules/openapi-types": {
"version": "12.1.3",
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
"integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
"dev": true,
"peer": true
},
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@ -4875,8 +5346,7 @@
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"devOptional": true
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/progress": {
"version": "2.0.3",
@ -4912,6 +5382,11 @@
"node": ">=0.6"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -5073,6 +5548,11 @@
"node": ">=0.10.0"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@ -5175,8 +5655,7 @@
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"devOptional": true
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/safe-regex": {
"version": "1.1.0",
@ -5250,6 +5729,18 @@
"node": ">=0.10.0"
}
},
"node_modules/sha1": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
"integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==",
"dependencies": {
"charenc": ">= 0.0.1",
"crypt": ">= 0.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -5541,6 +6032,14 @@
}
}
},
"node_modules/sqlstring": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
"integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/sshpk": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
@ -5594,7 +6093,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"devOptional": true,
"dependencies": {
"safe-buffer": "~5.1.0"
}
@ -5691,6 +6189,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
"dev": true,
"dependencies": {
"@apidevtools/swagger-parser": "10.0.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/swagger-ui-dist": {
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.19.1.tgz",
"integrity": "sha512-n/gFn+R7G/BXWwl5UZLw6F1YgWOlf3zkwGlsPhTMhNtAAolBGKg0JS5b2RKt5NI6/hSopVaSrki2wTIMUDDy2w==",
"dev": true
},
"node_modules/table": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
@ -6017,6 +6533,15 @@
"integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
"deprecated": "Please see https://github.com/lydell/urix#deprecated"
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@ -6028,8 +6553,7 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"devOptional": true
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "3.4.0",
@ -6059,6 +6583,15 @@
"node": ">= 0.10"
}
},
"node_modules/validator": {
"version": "13.11.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz",
"integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@ -6149,6 +6682,26 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/z-schema": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
"dev": true,
"dependencies": {
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"validator": "^13.7.0"
},
"bin": {
"z-schema": "bin/z-schema"
},
"engines": {
"node": ">=8.0.0"
},
"optionalDependencies": {
"commander": "^9.4.1"
}
}
}
}

View File

@ -1,17 +1,24 @@
{
"name": "hapipal-boilerplate",
"name": "iut-encrypt-cemal",
"version": "3.0.0",
"main": "lib/index.js",
"scripts": {
"start": "node server",
"test": "lab -a @hapi/code -L",
"test": "lab -a @hapi/code -I \"__core-js_shared__,CSS,regeneratorRuntime,core\" -L",
"lint": "eslint ."
},
"dependencies": {
"@hapi/boom": "9.x.x",
"@hapi/jwt": "^3.2.0",
"@hapipal/haute-couture": "4.x.x",
"@hapipal/schmervice": "^3.0.0",
"@hapipal/schwifty": "6.x.x",
"amqplib": "^0.10.3",
"iut-encrypt-cemal": "^1.0.0",
"joi": "17.x.x",
"json2csv": "^6.0.0-alpha.2",
"mysql": "^2.18.1",
"nodemailer": "^6.9.8",
"objection": "2.x.x"
},
"peerDependencies": {
@ -24,7 +31,9 @@
"@hapi/glue": "8.x.x",
"@hapi/hapi": "20.x.x",
"@hapi/hoek": "9.x.x",
"@hapi/inert": "6.x.x",
"@hapi/lab": "24.x.x",
"@hapi/vision": "6.x.x",
"@hapipal/confidence": "6.x.x",
"@hapipal/hpal": "3.x.x",
"@hapipal/hpal-debug": "2.x.x",
@ -33,6 +42,7 @@
"dotenv": "8.x.x",
"eslint": "7.x.x",
"exiting": "6.x.x",
"hapi-swagger": "14.x.x",
"knex": "0.21.x",
"sqlite3": "5.x.x"
}

View File

@ -34,6 +34,9 @@ module.exports = new Confidence.Store({
plugin: '../lib', // Main plugin
options: {}
},
{
plugin: './plugins/swagger'
},
{
plugin : '@hapipal/schwifty',
options : {
@ -42,13 +45,13 @@ module.exports = new Confidence.Store({
$base : {
migrateOnStart : true,
knex : {
client: 'sqlite3',
useNullAsDefault: true, // Suggested for sqlite3
client : 'mysql',
connection : {
filename: ':memory:'
},
migrations: {
stub: Schwifty.migrationsStubPath
host : 'localhost',
user : 'root',
password : 'hapi',
database : 'user',
port : 3307
}
}
},

View File

@ -17,7 +17,15 @@ module.exports = {
options: {
info: {
version: Package.version
},
securityDefinitions : {
'jwt' : {
'type' : 'apiKey',
'name' : 'Authorization',
'in' : 'header'
}
},
security : [{ 'jwt' : [] }],
}
}
]);