diff --git a/api/openapi.yaml b/api/openapi.yaml index b7c632336b2f05bba0151fe038db4b09dc6629d8..4d5a286a525d695aa87d78302908daa4f8d45ec2 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -26,7 +26,39 @@ tags: - name: user description: Operations about user paths: - /ad: + /graphql: + post: + tags: + - graphql + summary: GraphQL Endpoint + description: Execute GraphQL queries + operationId: executeGraphQLQuery + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + query: + type: string + variables: + type: object + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + properties: + data: + type: object + errors: + type: array + items: + type: object + /announcements: post: tags: - ad @@ -41,7 +73,7 @@ paths: schema: $ref: '#/components/schemas/Ad' security: - - bearerAuth: [] + - bearerAuth: [ ] responses: "200": description: Successful operation @@ -52,7 +84,27 @@ paths: "405": description: Invalid input x-swagger-router-controller: Ad - /update/{id}: + + get: + tags: + - ad + summary: Obtenir la liste des annonces + description: Récupère la liste des annonces + operationId: getAds + security: + - bearerAuth: [ ] + responses: + "200": + description: Succès. Liste des annonces récupérée avec succès. + content: + application/json: + schema: + $ref: '#/components/schemas/AnnouncementList' + "500": + description: Erreur serveur interne. Veuillez réessayer plus tard. + x-swagger-router-controller: Ad + + /announcements/update/{id}: put: tags: - ad @@ -60,12 +112,12 @@ paths: description: Met à jour une annonce. operationId: updateAd parameters: - - name: id - in: path - description: ID de l'annonce à mettre à jour - required: true - schema: - type: string + - name: id + in: path + description: ID de l'annonce à mettre à jour + required: true + schema: + type: string requestBody: description: Annonce à mettre à jour required: true @@ -74,7 +126,7 @@ paths: schema: $ref: '#/components/schemas/UpdateAd' security: - - bearerAuth: [] + - bearerAuth: [ ] responses: '200': description: Succès. Renvoie les détails de l'annonce mise à jour. @@ -83,6 +135,7 @@ paths: '404': description: Non trouvé. L'annonce avec cet ID n'a pas été trouvée. x-swagger-router-controller: Ad + /announcements/delete/{id}: post: tags: @@ -112,25 +165,6 @@ paths: '500': description: Erreur serveur interne. Veuillez réessayer plus tard. x-swagger-router-controller: Ad - /announcements: - get: - tags: - - ad - summary: Obtenir la liste des annonces - description: Récupère la liste des annonces - operationId: getAds - security: - - bearerAuth: [] - responses: - "200": - description: Succès. Liste des annonces récupérée avec succès. - content: - application/json: - schema: - $ref: '#/components/schemas/AnnouncementList' - "500": - description: Erreur serveur interne. Veuillez réessayer plus tard. - x-swagger-router-controller: Ad /announcements/{id}: get: tags: @@ -241,16 +275,8 @@ paths: application/json: schema: $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' security: - - oAuthSample: - - write_pets - - read_pets + - bearerAuth: [ ] responses: default: description: successful operation @@ -258,32 +284,29 @@ paths: application/json: schema: $ref: '#/components/schemas/User' - x-swagger-router-controller: User + /user/login: - get: + post: tags: - user summary: Logs user into the system description: "" operationId: loginUser - parameters: - - name: username - in: query - description: The user name for login - required: true - style: form - explode: true - schema: - type: string - - name: password - in: query - description: The password for login in clear text - required: true - style: form - explode: true - schema: - type: string + requestBody: + description: User credentials for login + content: + application/json: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password responses: "200": description: successful operation @@ -303,24 +326,25 @@ paths: type: string format: date-time content: - application/xml: + application/json: schema: - type: string - x-content-type: application/xml - + type: object + properties: + token: + type: string "400": description: Invalid username/password supplied x-swagger-router-controller: User + /user/logout: - get: + post: tags: - user summary: Logs out current logged in user session description: "" operationId: logoutUser - parameters: [] security: - - bearerAuth: [] + - bearerAuth: [ ] responses: default: description: successful operation diff --git a/controllers/Ad.js b/controllers/Ad.js index 8ca510270b330a699abaa02f43f24fd490537bc4..dce6b628bbdd12b2593e0bcdbd0865622f92b5ac 100644 --- a/controllers/Ad.js +++ b/controllers/Ad.js @@ -1,92 +1,80 @@ -'use strict'; +const express = require('express'); +const router = express.Router(); +const AdService = require('../service/AdService'); +const utils = require('../utils/writer.js'); -var utils = require('../utils/writer.js'); -var Ad = require('../service/AdService'); // Assurez-vous d'importer le service Announcement -var User = require('../service/UserService'); - -module.exports.addAd = function addAd (req, res, next, body) { - const token = req.headers.authorization.split(' ')[1]; - Ad.addAd(body, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); +const extractToken = (req, res, next) => { + req.token = req.headers.authorization ? req.headers.authorization.split(' ')[1] : null; + next(); }; -module.exports.updateAd = function updateAd (req, res, next) { - const token = req.headers.authorization.split(' ')[1]; - Ad.updateAd(req.openapi.pathParams.id, req.body, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; +router.post('/', extractToken, async (req, res) => { + try { + const response = await AdService.addAd(req.body, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); -module.exports.deleteAd = function deleteAd(req, res, next, announcementId) { - const token = req.headers.authorization.split(' ')[1]; - Ad.deleteAd(announcementId, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (response) { - utils.writeJson(res, response); - }); -}; +router.put('/update/:id', extractToken, async (req, res) => { + try { + const response = await AdService.updateAd(req.params.id, req.body, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); -module.exports.getAds = function getAnnouncements(req, res) { - const token = req.headers.authorization.split(' ')[1]; - Ad.getAds(token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (error) { - res.status(500).json({ message: error.message }); - }); -}; +router.post('/delete/:id', extractToken, async (req, res) => { + try { + const response = await AdService.deleteAd(req.params.id, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); -module.exports.getAdById = function getAnnouncementById(req, res) { - const announcementId = req.openapi.pathParams.id; - const token = req.headers.authorization.split(' ')[1]; +router.get('/', extractToken, async (req, res) => { + try { + const response = await AdService.getAds(req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); - Ad.getAdById(announcementId, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (error) { - res.status(500).json({ message: error.message }); - }); -}; +router.get('/:id', extractToken, async (req, res) => { + try { + const response = await AdService.getAdById(req.params.id, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); -exports.askQuestion = async function(req, res) { - const announcementId = req.openapi.pathParams.id; +router.put('/:id/ask', extractToken, async (req, res) => { + const announcementId = req.params.id; const { question } = req.body; - const token = req.headers.authorization.split(' ')[1]; - - Ad.askQuestion(announcementId, question, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (error) { - res.status(500).json({ message: error.message }); - }); -}; + try { + const response = await AdService.askQuestion(announcementId, question, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); -exports.answerQuestion = async function(req, res) { - const announcementId = req.openapi.pathParams.id; - const questionId = req.openapi.pathParams.questionId; +router.put('/:id/question/:questionId/answer', extractToken, async (req, res) => { + const announcementId = req.params.id; + const questionId = req.params.questionId; const { answer } = req.body; - const token = req.headers.authorization.split(' ')[1]; + try { + const response = await AdService.answerQuestion(announcementId, questionId, answer, req.token); + utils.writeJson(res, response); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}); - Ad.answerQuestion(announcementId, questionId, answer, token) - .then(function (response) { - utils.writeJson(res, response); - }) - .catch(function (error) { - res.status(500).json({ message: error.message }); - }); -}; \ No newline at end of file +module.exports = router; diff --git a/controllers/User.js b/controllers/User.js index 6218f4818bca2b0f31705a6438e9dd560c8f562e..bb754120881c0d00637dbd18a1483c6a4e731998 100644 --- a/controllers/User.js +++ b/controllers/User.js @@ -1,16 +1,12 @@ -'use strict'; - -var utils = require('../utils/writer.js'); -var User = require('../service/UserService'); -var passport = require('../passeport-config'); -var UserModel = require('../models/User'); - +const express = require('express'); +const passport = require('../passeport-config'); const jwt = require('jsonwebtoken'); -const { extractUserFromToken } = require( '../service/UserService'); -const secretKey = 'secretKey'; +const utils = require('../utils/writer.js'); +const User = require('../service/UserService'); + +const authRouter = express.Router(); -// passport.use(UserModel.createStrategy()); -module.exports.createUser = async function(req, res) { +authRouter.post('/user', async (req, res) => { try { const { username, password, isAgent } = req.body; await User.createUser(username, password, isAgent); @@ -18,47 +14,34 @@ module.exports.createUser = async function(req, res) { } catch (error) { utils.writeJson(res, { error: error.message }); } -}; +}); -module.exports.loginUser = async function loginUser(req, res, next) { +authRouter.post('/login', async (req, res, next) => { try { passport.authenticate('local', (err, user, info) => { if (err) { - return res.status(500).send(err); // Erreur interne du serveur + return res.status(500).send(err); // Internal Server Error } if (!user) { - return res.status(401).send('Invalid username or password.'); // Non autorisé + return res.status(401).send('Invalid username or password.'); // Unauthorized } const token = jwt.sign({ username: user.username }, 'secretKey', { expiresIn: '1h' }); - // User.loginUser() - // .then(function (response) { - // utils.writeJson(res, response); - // }) - // .catch(function (response) { - // utils.writeJson(res, response); - // }); return res.status(200).json({ token }); })(req, res, next); } catch (error) { console.error("Erreur lors de la tentative de connexion :", error); return res.status(500).send(error); } -} +}); -module.exports.logoutUser = async function(req, res, next) { +authRouter.post('/logout', async (req, res) => { try { - /* - req.logout(function(err) { - if (err) { - return next(err); - } - res.redirect('/'); - }); - */ + // Perform logout logic if needed return res.status(200).send('Logout successful.'); // Success } catch (error) { console.error("Erreur lors de la déconnexion de l'utilisateur :", error); return res.status(500).send(error); } -}; +}); +module.exports = authRouter; diff --git a/data-access/connection.js b/data-access/connection.js index c1c6259e9903a893cde2be78662f6f10837b89a6..40cc13b579c8fa701ece1ea150e98e2b8a89e9fd 100644 --- a/data-access/connection.js +++ b/data-access/connection.js @@ -2,7 +2,7 @@ const mongoose = require('mongoose'); require('dotenv').config(); const dbName = process.env.DB_NAME; -const url = `mongodb://mongodb:27017/${dbName}`; +const url = `mongodb://172.24.0.2:27017/${dbName}`; const connectToDatabase = async () => { try { diff --git a/index.js b/index.js index e7216e0e0c024ce35991856983dfc2d24606df05..f2b9f4f363b3d3892434fadb93d34c69235a00c8 100644 --- a/index.js +++ b/index.js @@ -1,42 +1,100 @@ -'use strict'; +const express = require('express'); +const session = require('express-session'); +const swaggerUi = require('swagger-ui-express'); +const { makeExecutableSchema } = require('@graphql-tools/schema'); +const { createHandler } = require('graphql-http/lib/use/express'); +const expressPlayground = require('graphql-playground-middleware-express').default; +const YAML = require('yamljs'); +const swaggerJsdoc = require('swagger-jsdoc'); +const swaggerParser = require('swagger-parser'); +const connectToDatabase = require('./data-access/connection'); +const passport = require('./passeport-config'); +const apiRouter = require('./controllers/Ad'); +const authRouter = require('./controllers/User'); +const utils = require('./utils/writer'); +const path = require('path'); -var path = require('path'); -var http = require('http'); -var session = require('express-session'); +const app = express(); +const serverPort = 8080; -var oas3Tools = require('oas3-tools'); -var serverPort = 8080; +// Middleware for parsing JSON +app.use(express.json()); -// swaggerRouter configuration -var options = { - routing: { - controllers: path.join(__dirname, './controllers') +const options = { + definition: { + openapi: '3.0.3', + info: { + title: 'Api Ads', + version: '1.0.0', + description: 'Ads API', + }, }, + apis: ['./controllers/*.js'], }; -var expressAppConfig = oas3Tools.expressAppConfig(path.join(__dirname, 'api/openapi.yaml'), options); -var app = expressAppConfig.getApp(); - -const connectToDatabase = require('./data-access/connection'); -const passport = require("./passeport-config"); +const openApiPath = path.join(__dirname, 'api', 'openapi.yaml'); +const openApiDocument = YAML.load(openApiPath); -// app.use(session({ secret: 'fifiHajar', resave: true, saveUninitialized: true })); -// app.use(passport.initialize()); -// app.use(passport.session()); +swaggerParser.validate(openApiDocument, (err, api) => { + if (err) { + console.error('Error validating OpenAPI document:', err); + process.exit(1); + } else { + console.log('OpenAPI document is valid'); + } +}); -// Connect to the database -connectToDatabase() - .then(() => { +const swaggerSpec = swaggerJsdoc(options); +// Your GraphQL schema and resolvers +const typeDefs = ` + type Query { + hello: String + users(filterName: String): [User] + user(id: ID!): User + goods: [Good] + } + type Mutation { + createPurchaseForUser(userId: ID!, goodId: ID!, quantity: Int!): Purchase + } + type User { + id: ID! + name: String! + email: String! + purchases: [Purchase]! + } + type Purchase { + id: ID! + date: Date + good: Good + quantity: Int + } + type Good { + id: ID! + name: String! + price: Float! + } + scalar Date +`; +const resolvers = { + // Your resolvers here +}; +const schema = makeExecutableSchema({ typeDefs, resolvers }); +app.use('/docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, swaggerSpec)); +app.get('/graphql-playground', expressPlayground({ endpoint: '/graphql' })); +app.post('/graphql', createHandler({ schema })); +app.use('/announcements', apiRouter); +app.use('/user', authRouter); - // Initialize the Swagger middleware - http.createServer(app).listen(serverPort, function () { - console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort); +connectToDatabase() + .then(() => { + app.listen(serverPort, () => { + console.log(`Your server is listening on port ${serverPort} (http://localhost:${serverPort})`); console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort); + console.log('GraphQL Playground is available on http://localhost:%d/graphql-playground', serverPort); }); }) .catch(error => { console.error('Error connecting to the database:', error); }); - diff --git a/package-lock.json b/package-lock.json index 0fdce2eee53bfecc1c5f91151b53c52b12aab4fe..813703ddf80309c55248943daf9bc962a5bfb1b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,24 @@ "version": "1.0.11", "license": "Unlicense", "dependencies": { + "@graphql-tools/schema": "^10.0.0", "connect": "^3.2.0", "dotenv": "^16.3.1", + "express": "^4.18.2", "express-session": "^1.17.3", + "graphql": "^16.8.1", + "graphql-http": "^1.22.0", + "graphql-playground-middleware-express": "^1.7.23", "js-yaml": "^3.3.0", "jsonwebtoken": "^9.0.2", "mongoose": "^7.6.3", "oas3-tools": "^2.2.3", "passport": "^0.6.0", "passport-local": "^1.0.0", - "passport-local-mongoose": "^8.0.0" + "passport-local-mongoose": "^8.0.0", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0", + "yamljs": "^0.3.0" }, "devDependencies": { "nodemon": "^3.0.1" @@ -51,6 +59,92 @@ "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==", + "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==" + }, + "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==", + "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/@graphql-tools/merge": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.0.tgz", + "integrity": "sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==", + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/schema": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.0.tgz", + "integrity": "sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==", + "dependencies": { + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/utils": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.8.tgz", + "integrity": "sha512-yjyA8ycSa1WRlJqyX/aLqXeE5DvF/H02+zXMUFnCzIDrj0UvLMUrxhmVFnMK0Q2n3bh4uuTeY3621m5za9ovXw==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "cross-inspect": "1.0.0", + "dset": "^3.1.2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -253,8 +347,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/basic-auth": { "version": "2.0.1", @@ -313,7 +406,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -414,11 +506,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -529,6 +625,22 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cross-inspect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.0.tgz", + "integrity": "sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/cssfilter": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", + "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -579,6 +691,17 @@ "node": ">=0.8.0" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dotenv": { "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", @@ -590,6 +713,14 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, + "node_modules/dset": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -628,6 +759,14 @@ "node": ">=4" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -970,6 +1109,11 @@ "node": ">= 0.6" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1011,6 +1155,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -1034,6 +1197,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-http": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/graphql-http/-/graphql-http-1.22.0.tgz", + "integrity": "sha512-9RBUlGJWBFqz9LwfpmAbjJL/8j/HCNkZwPBU5+Bfmwez+1Ay43DocMNQYpIWsWqH0Ftv6PTNAh2aRnnMCBJgLw==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "graphql": ">=0.11 <=16" + } + }, + "node_modules/graphql-playground-html": { + "version": "1.6.30", + "resolved": "https://registry.npmjs.org/graphql-playground-html/-/graphql-playground-html-1.6.30.tgz", + "integrity": "sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==", + "dependencies": { + "xss": "^1.0.6" + } + }, + "node_modules/graphql-playground-middleware-express": { + "version": "1.7.23", + "resolved": "https://registry.npmjs.org/graphql-playground-middleware-express/-/graphql-playground-middleware-express-1.7.23.tgz", + "integrity": "sha512-M/zbTyC1rkgiQjFSgmzAv6umMHOphYLNWZp6Ye5QrD77WfGOOoSqDsVmGUczc2pDkEPEzzGB/bvBO5rdzaTRgw==", + "dependencies": { + "graphql-playground-html": "^1.6.30" + }, + "peerDependencies": { + "express": "^4.16.2" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1124,6 +1325,15 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1296,6 +1506,11 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" }, + "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==" + }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -1316,6 +1531,11 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -1403,7 +1623,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1744,6 +1963,14 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/ono/-/ono-7.1.3.tgz", @@ -1752,6 +1979,12 @@ "@jsdevtools/ono": "7.1.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==", + "peer": true + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1809,6 +2042,14 @@ "node": ">= 0.4.0" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-to-regexp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", @@ -2187,6 +2428,82 @@ "node": ">=4" } }, + "node_modules/swagger-jsdoc": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", + "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", + "dependencies": { + "commander": "6.2.0", + "doctrine": "3.0.0", + "glob": "7.1.6", + "lodash.mergewith": "^4.6.2", + "swagger-parser": "^10.0.3", + "yaml": "2.0.0-1" + }, + "bin": { + "swagger-jsdoc": "bin/swagger-jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/swagger-jsdoc/node_modules/commander": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/swagger-jsdoc/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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==", + "dependencies": { + "@apidevtools/swagger-parser": "10.0.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swagger-ui-dist": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.9.3.tgz", + "integrity": "sha512-/OgHfO96RWXF+p/EOjEnvKNEh94qAG/VHukgmVKh5e6foX9kas1WbjvQnDDj0sSTAMr9MHRBqAWytDcQi0VOrg==" + }, + "node_modules/swagger-ui-express": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.0.tgz", + "integrity": "sha512-tsU9tODVvhyfkNSvf03E6FAk+z+5cU3lXAzMy6Pv4av2Gt2xA0++fogwC4qo19XuFf6hdxevPuVCSKFuMHJhFA==", + "dependencies": { + "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2230,6 +2547,11 @@ "node": ">=12" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -2306,6 +2628,22 @@ "node": ">= 0.4.0" } }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/value-or-promise": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", + "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==", + "engines": { + "node": ">=12" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2334,6 +2672,26 @@ "node": ">=12" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xss": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.14.tgz", + "integrity": "sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==", + "dependencies": { + "commander": "^2.20.3", + "cssfilter": "0.0.10" + }, + "bin": { + "xss": "bin/xss" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -2346,6 +2704,55 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "2.0.0-1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", + "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dependencies": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + }, + "bin": { + "json2yaml": "bin/json2yaml", + "yaml2json": "bin/yaml2json" + } + }, + "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==", + "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" + } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } } } } diff --git a/package.json b/package.json index a2d30d0ba57dbc5ebf1e39e36ec1054dc2749b5c..b305434cf99351f7847d777320086192d3ea4f08 100644 --- a/package.json +++ b/package.json @@ -21,16 +21,24 @@ "license": "Unlicense", "private": true, "dependencies": { + "@graphql-tools/schema": "^10.0.0", "connect": "^3.2.0", "dotenv": "^16.3.1", + "express": "^4.18.2", "express-session": "^1.17.3", + "graphql": "^16.8.1", + "graphql-http": "^1.22.0", + "graphql-playground-middleware-express": "^1.7.23", "js-yaml": "^3.3.0", "jsonwebtoken": "^9.0.2", "mongoose": "^7.6.3", "oas3-tools": "^2.2.3", "passport": "^0.6.0", "passport-local": "^1.0.0", - "passport-local-mongoose": "^8.0.0" + "passport-local-mongoose": "^8.0.0", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.0", + "yamljs": "^0.3.0" }, "devDependencies": { "nodemon": "^3.0.1"