diff --git a/.env b/.env new file mode 100644 index 0000000..935f278 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +EMAIL_USER=adeline.ondricka5@ethereal.email +EMAIL_PASSWORD=B4khRtXZPNqtr58bAu +EMAIL_FROM=adeline.ondricka5@ethereal.email \ No newline at end of file diff --git a/lib/auth/default.js b/lib/auth/default.js new file mode 100644 index 0000000..2344418 --- /dev/null +++ b/lib/auth/default.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = 'jwt'; \ No newline at end of file diff --git a/lib/auth/strategies/jwt.js b/lib/auth/strategies/jwt.js new file mode 100644 index 0000000..6a7e694 --- /dev/null +++ b/lib/auth/strategies/jwt.js @@ -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 + }; + } + } +}; diff --git a/lib/migrations/0-favorites.js b/lib/migrations/0-favorites.js new file mode 100644 index 0000000..fa0c319 --- /dev/null +++ b/lib/migrations/0-favorites.js @@ -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'); + } + +} \ No newline at end of file diff --git a/lib/migrations/0-user.js b/lib/migrations/0-user.js new file mode 100644 index 0000000..3d8ae90 --- /dev/null +++ b/lib/migrations/0-user.js @@ -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'); + }); + } +}; diff --git a/lib/migrations/1-user.js b/lib/migrations/1-user.js new file mode 100644 index 0000000..3d8ae90 --- /dev/null +++ b/lib/migrations/1-user.js @@ -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'); + }); + } +}; diff --git a/lib/migrations/2-user.js b/lib/migrations/2-user.js new file mode 100644 index 0000000..8fbcc55 --- /dev/null +++ b/lib/migrations/2-user.js @@ -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'); + }); + } +}; diff --git a/lib/migrations/3-user.js b/lib/migrations/3-user.js new file mode 100644 index 0000000..58dba54 --- /dev/null +++ b/lib/migrations/3-user.js @@ -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'); + }); + } +}; diff --git a/lib/migrations/4-user.js b/lib/migrations/4-user.js new file mode 100644 index 0000000..4a63ce5 --- /dev/null +++ b/lib/migrations/4-user.js @@ -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'); + }); + } +}; diff --git a/lib/models/favorite.js b/lib/models/favorite.js new file mode 100644 index 0000000..a8c6622 --- /dev/null +++ b/lib/models/favorite.js @@ -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') + }); + } + + +} \ No newline at end of file diff --git a/lib/models/movie.js b/lib/models/movie.js new file mode 100644 index 0000000..9d5ff0f --- /dev/null +++ b/lib/models/movie.js @@ -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(); + } + +} \ No newline at end of file diff --git a/lib/models/user.js b/lib/models/user.js new file mode 100644 index 0000000..4ddffbb --- /dev/null +++ b/lib/models/user.js @@ -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); + } + } + +}; diff --git a/lib/plugins/@hapi.jwt.js b/lib/plugins/@hapi.jwt.js new file mode 100644 index 0000000..7a53d76 --- /dev/null +++ b/lib/plugins/@hapi.jwt.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + plugins: { + options: {} + } +}; diff --git a/lib/plugins/@hapipal.schmervice.js b/lib/plugins/@hapipal.schmervice.js new file mode 100644 index 0000000..26853c9 --- /dev/null +++ b/lib/plugins/@hapipal.schmervice.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = { + options: { } +}; diff --git a/lib/routes/favorites.js b/lib/routes/favorites.js new file mode 100644 index 0000000..1c0c544 --- /dev/null +++ b/lib/routes/favorites.js @@ -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 + }); + } + } +] \ No newline at end of file diff --git a/lib/routes/movie.js b/lib/routes/movie.js new file mode 100644 index 0000000..d8b28ff --- /dev/null +++ b/lib/routes/movie.js @@ -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', + '\n' + + '\n' + + '\n' + + '\n' + + ' \n' + + ' \n' + + ' A new movie was added !\n' + + ' \n' + + '\n' + + '\n' + + '\n' + + '
\n' + + '
\n' + + '

A new movie was added !

\n' + + '
\n' + + '
\n' + + '

Hello,

\n' + + '

A new movie was just added to the library.

\n' + + '

Go discover it now !

\n' + + ' Discover new movie\n' + + '

Happy exploring!

\n' + + '
\n' + + ' \n' + + '
\n' + + '\n' + + '\n' + + '\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', + '\n' + + '\n' + + '\n' + + '\n' + + ' \n' + + ' \n' + + ' A movie was updated !\n' + + ' \n' + + '\n' + + '\n' + + '\n' + + '
\n' + + '
\n' + + '

A movie was updated !

\n' + + '
\n' + + '
\n' + + '

Hello,

\n' + + '

The movie ' + request.payload.title + ' was just updated in the library.

\n' + + '

Go check it out now !

\n' + + ' Discover updated movie\n' + + '

Happy exploring!

\n' + + '
\n' + + ' \n' + + '
\n' + + '\n' + + '\n' + + '\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); + } + } + } + +] \ No newline at end of file diff --git a/lib/routes/user.js b/lib/routes/user.js index 5c2a6fd..6bef206 100644 --- a/lib/routes/user.js +++ b/lib/routes/user.js @@ -1,13 +1,257 @@ 'use strict'; -module.exports = { - method: 'get', - path: '/user', - options: { - tags: ['api'], - }, - handler: async (request, h) => { +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', + '\n' + + '\n' + + '\n' + + '\n' + + ' \n' + + ' \n' + + ' Welcome to Our Application!\n' + + ' \n' + + '\n' + + '\n' + + '\n' + + '
\n' + + '
\n' + + '

Welcome to Our Application!

\n' + + '
\n' + + '
\n' + + '

Hello,

\n' + + '

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.

\n' + + '

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.

\n' + + ' Log In Now\n' + + '

Happy exploring!

\n' + + '
\n' + + ' \n' + + '
\n' + + '\n' + + '\n' + + '\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(); + + // 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); + } + }, - return { firstName: 'John', lastName: 'Doe'}; } -}; + +]; diff --git a/lib/services/email.js b/lib/services/email.js new file mode 100644 index 0000000..cd05ce8 --- /dev/null +++ b/lib/services/email.js @@ -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 + } + } +} \ No newline at end of file diff --git a/lib/services/favorite.js b/lib/services/favorite.js new file mode 100644 index 0000000..05d2774 --- /dev/null +++ b/lib/services/favorite.js @@ -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}); + } +} \ No newline at end of file diff --git a/lib/services/logo.png b/lib/services/logo.png new file mode 100644 index 0000000..66406c4 Binary files /dev/null and b/lib/services/logo.png differ diff --git a/lib/services/movie.js b/lib/services/movie.js new file mode 100644 index 0000000..8fbd413 --- /dev/null +++ b/lib/services/movie.js @@ -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; + } + } + +} \ No newline at end of file diff --git a/lib/services/rabbitmq.js b/lib/services/rabbitmq.js new file mode 100644 index 0000000..6b461f1 --- /dev/null +++ b/lib/services/rabbitmq.js @@ -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; + } + } + + +}; diff --git a/lib/services/templates/welcome.html b/lib/services/templates/welcome.html new file mode 100644 index 0000000..9e77faa --- /dev/null +++ b/lib/services/templates/welcome.html @@ -0,0 +1,82 @@ + + + + + + + Welcome to Our Application! + + + + +
+
+ +

Welcome to Our Application!

+
+
+

Hello,

+

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.

+

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.

+ Log In Now +

Happy exploring!

+
+ +
+ + + diff --git a/lib/services/user.js b/lib/services/user.js new file mode 100644 index 0000000..184f9e3 --- /dev/null +++ b/lib/services/user.js @@ -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; + + } + + +} diff --git a/package-lock.json b/package-lock.json index 5b464bb..7c0e62c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" + } } } } diff --git a/package.json b/package.json index 9041b92..823d048 100644 --- a/package.json +++ b/package.json @@ -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" } diff --git a/server/manifest.js b/server/manifest.js index fa9797d..2010831 100644 --- a/server/manifest.js +++ b/server/manifest.js @@ -35,25 +35,28 @@ module.exports = new Confidence.Store({ options: {} }, { - plugin: '@hapipal/schwifty', - options: { - $filter: 'NODE_ENV', - $default: {}, - $base: { - migrateOnStart: true, - knex: { - client: 'sqlite3', - useNullAsDefault: true, // Suggested for sqlite3 - connection: { - filename: ':memory:' - }, - migrations: { - stub: Schwifty.migrationsStubPath + plugin: './plugins/swagger' + }, + { + plugin : '@hapipal/schwifty', + options : { + $filter : 'NODE_ENV', + $default : {}, + $base : { + migrateOnStart : true, + knex : { + client : 'mysql', + connection : { + host : 'localhost', + user : 'root', + password : 'hapi', + database : 'user', + port : 3307 } } }, - production: { - migrateOnStart: false + production : { + migrateOnStart : false } } }, diff --git a/server/plugins/swagger.js b/server/plugins/swagger.js index 19595d1..ab052ba 100644 --- a/server/plugins/swagger.js +++ b/server/plugins/swagger.js @@ -17,9 +17,17 @@ module.exports = { options: { info: { version: Package.version - } + }, + securityDefinitions : { + 'jwt' : { + 'type' : 'apiKey', + 'name' : 'Authorization', + 'in' : 'header' + } + }, + security : [{ 'jwt' : [] }], } } ]); } -}; \ No newline at end of file +};