feat: Add Swagger API documentation

This commit introduces Swagger API documentation for all endpoints in the
application.

- Installs  and .
- Configures Swagger in  to generate and serve API documentation
  at .
- Adds JSDoc-style Swagger annotations to all routes in  and
  the  directory (, , ,
  , , ).
- Defines a cookie-based security scheme for authenticated routes.

This allows for interactive API documentation and testing via the
endpoint.
This commit is contained in:
Adolfo Reyna
2025-07-17 09:52:37 -04:00
parent 0a48327e93
commit 148ed696b2
9 changed files with 1891 additions and 10 deletions

294
index.js
View File

@@ -39,9 +39,119 @@ app.use(limiter);
// Authentication // Authentication
const { signup, login, logout, resetPassword } = require('./auth/authEmail.js'); const { signup, login, logout, resetPassword } = require('./auth/authEmail.js');
/**
* @swagger
* /signup:
* post:
* summary: Signs up a new user
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* format: password
* responses:
* 200:
* description: The user was successfully signed up.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Bad request.
*/
app.route('/signup').get(signup).post(signup); app.route('/signup').get(signup).post(signup);
/**
* @swagger
* /login:
* post:
* summary: Logs in a user
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* password:
* type: string
* format: password
* responses:
* 200:
* description: The user was successfully logged in.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 401:
* description: Invalid credentials.
*/
app.route('/login').get(login).post(login); app.route('/login').get(login).post(login);
/**
* @swagger
* /logout:
* get:
* summary: Logs out a user
* tags: [Auth]
* responses:
* 200:
* description: The user was successfully logged out.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
*/
app.get('/logout', logout); app.get('/logout', logout);
/**
* @swagger
* /resetPassword:
* post:
* summary: Resets a user's password
* tags: [Auth]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* format: email
* responses:
* 200:
* description: A password reset link has been sent to the user's email.
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Bad request.
*/
app.route('/resetPassword').post(resetPassword); app.route('/resetPassword').post(resetPassword);
// Routes // Routes
@@ -61,6 +171,42 @@ app.use('/songs', sessionChecker, songsRoute);
const subsplashRoute = require('./routes/subsplash.js'); const subsplashRoute = require('./routes/subsplash.js');
app.use('/subsplash', subsplashRoute); app.use('/subsplash', subsplashRoute);
// Swagger API Docs
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const swaggerDefinition = {
openapi: '3.0.0',
info: {
title: 'EMI Backend API',
version: '1.0.0',
description: 'This is the REST API for the EMI Backend'
},
servers: [
{
url: 'http://localhost:3000',
description: 'Development server'
}
],
components: {
securitySchemes: {
cookieAuth: {
type: 'apiKey',
in: 'cookie',
name: 'user_sid'
}
}
}
};
const options = {
swaggerDefinition,
apis: ['./index.js', './routes/*.js']
};
const swaggerSpec = swaggerJSDoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
// Web Push Notifications // Web Push Notifications
const webPush = require('web-push'); const webPush = require('web-push');
const publicVapidKey = process.env.PUBLIC_VAPID_KEY; const publicVapidKey = process.env.PUBLIC_VAPID_KEY;
@@ -78,7 +224,31 @@ const DB = require("./mongoDB.js");
DB.getDB.then((DB) => { DB.getDB.then((DB) => {
console.log("Main logic: DB connected!"); console.log("Main logic: DB connected!");
// route for Home-Page /**
* @swagger
* /:
* get:
* summary: Returns basic information about the logged-in user
* tags: [General]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* userInfo:
* type: object
* profileInfo:
* type: object
* 401:
* description: Unauthorized
*/
app.get('/', sessionChecker, async (req, res) => { app.get('/', sessionChecker, async (req, res) => {
try { try {
const userInfo = req.userInfo; const userInfo = req.userInfo;
@@ -97,7 +267,38 @@ DB.getDB.then((DB) => {
} }
}); });
// Check for an invitation for an email /**
* @swagger
* /invite/{email}:
* get:
* summary: Checks if an invitation exists for a given email
* tags: [General]
* parameters:
* - in: path
* name: email
* required: true
* schema:
* type: string
* format: email
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* invitation:
* type: object
* 400:
* description: Provide a valid email
* 404:
* description: No invitation found for this email
* 409:
* description: This user is already registered
*/
app.get("/invite/:email", async (req, res) => { app.get("/invite/:email", async (req, res) => {
try { try {
const email = req.params.email.trim().toLowerCase(); const email = req.params.email.trim().toLowerCase();
@@ -130,7 +331,42 @@ DB.getDB.then((DB) => {
}); });
// Change the active profile for the user. /**
* @swagger
* /changeProfile:
* post:
* summary: Changes the active profile for the user
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* profileid:
* type: string
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* profile:
* type: object
* 400:
* description: Profile ID is required
* 403:
* description: Profile does not belong to the logged-in user
* 404:
* description: Profile does not exist
*/
app.post('/changeProfile', sessionChecker, async (req, res) => { app.post('/changeProfile', sessionChecker, async (req, res) => {
try { try {
const user_sid = getUserId(req); const user_sid = getUserId(req);
@@ -157,7 +393,38 @@ DB.getDB.then((DB) => {
} }
}); });
// This is the endpoint to refresh the push notification token /**
* @swagger
* /token:
* post:
* summary: Refreshes the push notification token
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* token:
* type: string
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* 400:
* description: Token is required
* 500:
* description: Failed to update token
*/
app.post('/token/', sessionChecker, async (req, res) => { app.post('/token/', sessionChecker, async (req, res) => {
try { try {
const profileid = getProfileId(req); const profileid = getProfileId(req);
@@ -179,7 +446,24 @@ DB.getDB.then((DB) => {
} }
}); });
// Used for webpush notifications /**
* @swagger
* /subscribe:
* post:
* summary: Subscribes a user to webpush notifications
* tags: [General]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* responses:
* 201:
* description: Created
*/
app.post('/subscribe', sessionChecker, async (req, res) => { app.post('/subscribe', sessionChecker, async (req, res) => {
const subscription = req.body; const subscription = req.body;
res.status(201).json({}); res.status(201).json({});

433
package-lock.json generated
View File

@@ -26,6 +26,8 @@
"posthog-node": "^4.4.1", "posthog-node": "^4.4.1",
"socket.io": "^4.6.1", "socket.io": "^4.6.1",
"stripe": "^8.178.0", "stripe": "^8.178.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"web-push": "^3.4.5" "web-push": "^3.4.5"
}, },
"devDependencies": { "devDependencies": {
@@ -34,6 +36,50 @@
"supertest": "^7.0.0" "supertest": "^7.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==",
"license": "MIT",
"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/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==",
"license": "MIT",
"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==",
"license": "MIT"
},
"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==",
"license": "MIT",
"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/@isaacs/cliui": { "node_modules/@isaacs/cliui": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -137,6 +183,12 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1" "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/@mapbox/node-pre-gyp": { "node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
@@ -167,6 +219,13 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@scarf/scarf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
"hasInstallScript": true,
"license": "Apache-2.0"
},
"node_modules/@socket.io/component-emitter": { "node_modules/@socket.io/component-emitter": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
@@ -185,6 +244,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "16.10.2", "version": "16.10.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz",
@@ -305,7 +370,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0" "license": "Python-2.0"
}, },
"node_modules/array-flatten": { "node_modules/array-flatten": {
@@ -516,6 +580,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"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==",
"license": "MIT"
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
@@ -757,6 +827,15 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/commander": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/component-emitter": { "node_modules/component-emitter": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
@@ -983,6 +1062,18 @@
"node": ">=0.3.1" "node": ">=0.3.1"
} }
}, },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/dom-serializer": { "node_modules/dom-serializer": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -1221,6 +1312,15 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/etag": { "node_modules/etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
@@ -1884,7 +1984,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
@@ -1928,6 +2027,26 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.",
"license": "MIT"
},
"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==",
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
"license": "MIT"
},
"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==",
"license": "MIT"
},
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -2421,6 +2540,13 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"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==",
"license": "MIT",
"peer": true
},
"node_modules/optional-require": { "node_modules/optional-require": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
@@ -3251,6 +3377,83 @@
"url": "https://github.com/chalk/supports-color?sponsor=1" "url": "https://github.com/chalk/supports-color?sponsor=1"
} }
}, },
"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==",
"license": "MIT",
"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/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"license": "ISC",
"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==",
"license": "MIT",
"dependencies": {
"@apidevtools/swagger-parser": "10.0.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/swagger-ui-dist": {
"version": "5.27.0",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.0.tgz",
"integrity": "sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==",
"license": "Apache-2.0",
"dependencies": {
"@scarf/scarf": "=1.4.0"
}
},
"node_modules/swagger-ui-express": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
"license": "MIT",
"dependencies": {
"swagger-ui-dist": ">=5.0.0"
},
"engines": {
"node": ">= v0.10.32"
},
"peerDependencies": {
"express": ">=4.0.0 || >=5.0.0-beta"
}
},
"node_modules/tar": { "node_modules/tar": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
@@ -3326,6 +3529,15 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/validator": {
"version": "13.15.15",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz",
"integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -3563,6 +3775,15 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" "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==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/yargs": { "node_modules/yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@@ -3668,9 +3889,73 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "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==",
"license": "MIT",
"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==",
"license": "MIT",
"optional": true,
"engines": {
"node": "^12.20.0 || >=14"
}
} }
}, },
"dependencies": { "dependencies": {
"@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==",
"requires": {
"@jsdevtools/ono": "^7.1.3",
"@types/json-schema": "^7.0.6",
"call-me-maybe": "^1.0.1",
"js-yaml": "^4.1.0"
}
},
"@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=="
},
"@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=="
},
"@apidevtools/swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
"requires": {
"@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"
}
},
"@isaacs/cliui": { "@isaacs/cliui": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -3736,6 +4021,11 @@
} }
} }
}, },
"@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=="
},
"@mapbox/node-pre-gyp": { "@mapbox/node-pre-gyp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz",
@@ -3759,6 +4049,11 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"@scarf/scarf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
"integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ=="
},
"@socket.io/component-emitter": { "@socket.io/component-emitter": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
@@ -3777,6 +4072,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@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=="
},
"@types/node": { "@types/node": {
"version": "16.10.2", "version": "16.10.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.2.tgz",
@@ -3866,8 +4166,7 @@
"argparse": { "argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
"dev": true
}, },
"array-flatten": { "array-flatten": {
"version": "1.1.1", "version": "1.1.1",
@@ -4032,6 +4331,11 @@
"get-intrinsic": "^1.2.6" "get-intrinsic": "^1.2.6"
} }
}, },
"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=="
},
"camelcase": { "camelcase": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
@@ -4199,6 +4503,11 @@
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
}, },
"commander": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
"integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q=="
},
"component-emitter": { "component-emitter": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
@@ -4361,6 +4670,14 @@
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true "dev": true
}, },
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"requires": {
"esutils": "^2.0.2"
}
},
"dom-serializer": { "dom-serializer": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -4525,6 +4842,11 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true "dev": true
}, },
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
"etag": { "etag": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
@@ -4979,7 +5301,6 @@
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": { "requires": {
"argparse": "^2.0.1" "argparse": "^2.0.1"
} }
@@ -5012,6 +5333,21 @@
"p-locate": "^5.0.0" "p-locate": "^5.0.0"
} }
}, },
"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=="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
},
"lodash.mergewith": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
},
"log-symbols": { "log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -5346,6 +5682,12 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"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
},
"optional-require": { "optional-require": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
@@ -5940,6 +6282,58 @@
"has-flag": "^4.0.0" "has-flag": "^4.0.0"
} }
}, },
"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==",
"requires": {
"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"
},
"dependencies": {
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"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"
}
}
}
},
"swagger-parser": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
"integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
"requires": {
"@apidevtools/swagger-parser": "10.0.3"
}
},
"swagger-ui-dist": {
"version": "5.27.0",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.0.tgz",
"integrity": "sha512-tS6LRyBhY6yAqxrfsA9IYpGWPUJOri6sclySa7TdC7XQfGLvTwDY531KLgfQwHEtQsn+sT4JlUspbeQDBVGWig==",
"requires": {
"@scarf/scarf": "=1.4.0"
}
},
"swagger-ui-express": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
"integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
"requires": {
"swagger-ui-dist": ">=5.0.0"
}
},
"tar": { "tar": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
@@ -5996,6 +6390,11 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
}, },
"validator": {
"version": "13.15.15",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz",
"integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A=="
},
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -6154,6 +6553,11 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}, },
"yaml": {
"version": "2.0.0-1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ=="
},
"yargs": { "yargs": {
"version": "17.7.2", "version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
@@ -6226,6 +6630,25 @@
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true "dev": true
},
"z-schema": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
"integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
"requires": {
"commander": "^9.4.1",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"validator": "^13.7.0"
},
"dependencies": {
"commander": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
"optional": true
}
}
} }
} }
} }

View File

@@ -30,6 +30,8 @@
"posthog-node": "^4.4.1", "posthog-node": "^4.4.1",
"socket.io": "^4.6.1", "socket.io": "^4.6.1",
"stripe": "^8.178.0", "stripe": "^8.178.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"web-push": "^3.4.5" "web-push": "^3.4.5"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -13,11 +13,47 @@ const defaultBibleId = "592420522e16049f-01";
//getMedia('y42zyf3').then(console.log) //getMedia('y42zyf3').then(console.log)
DB.getDB.then((DB) => { DB.getDB.then((DB) => {
/**
* @swagger
* tags:
* name: Bible
* description: Bible API
*/
/**
* @swagger
* /bible:
* get:
* summary: Get a list of available Bibles
* tags: [Bible]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("", async (req, res) => { router.get("", async (req, res) => {
const bibles = await fetchAPI('bibles'); const bibles = await fetchAPI('bibles');
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/books:
* get:
* summary: Get the books of a Bible
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/books", async (req, res) => { router.get("/books", async (req, res) => {
const bibleId = req.query.bibleId || defaultBibleId; const bibleId = req.query.bibleId || defaultBibleId;
const bibles = await fetchAPI('bibles/' + bibleId +"/books"); const bibles = await fetchAPI('bibles/' + bibleId +"/books");
@@ -30,12 +66,56 @@ DB.getDB.then((DB) => {
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/books/{bookId}:
* get:
* summary: Get details for a specific book
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: bookId
* required: true
* schema:
* type: string
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/books/:bookId", async (req, res) => { router.get("/books/:bookId", async (req, res) => {
const bookId = req.params.bookId; const bookId = req.params.bookId;
const bibles = await fetchAPI('bibles/' + bibleId +"/books/" + bookId); const bibles = await fetchAPI('bibles/' + bibleId +"/books/" + bookId);
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/books/{bookId}/chapters:
* get:
* summary: Get the chapters of a book
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: bookId
* required: true
* schema:
* type: string
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/books/:bookId/chapters", async (req, res) => { router.get("/books/:bookId/chapters", async (req, res) => {
const bookId = req.params.bookId; const bookId = req.params.bookId;
const bibleId = req.query.bibleId || defaultBibleId; const bibleId = req.query.bibleId || defaultBibleId;
@@ -43,6 +123,28 @@ DB.getDB.then((DB) => {
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/chapters/{chapterId}:
* get:
* summary: Get the content of a chapter
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: chapterId
* required: true
* schema:
* type: string
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/chapters/:chapterId", async (req, res) => { router.get("/chapters/:chapterId", async (req, res) => {
const chapterId = req.params.chapterId; const chapterId = req.params.chapterId;
const bibleId = req.query.bibleId || defaultBibleId; const bibleId = req.query.bibleId || defaultBibleId;
@@ -50,6 +152,28 @@ DB.getDB.then((DB) => {
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/chapters/{chapterId}/verses:
* get:
* summary: Get the verses of a chapter
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: chapterId
* required: true
* schema:
* type: string
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/chapters/:chapterId/verses", async (req, res) => { router.get("/chapters/:chapterId/verses", async (req, res) => {
const chapterId = req.params.chapterId; const chapterId = req.params.chapterId;
const bibleId = req.query.bibleId || defaultBibleId; const bibleId = req.query.bibleId || defaultBibleId;
@@ -57,6 +181,33 @@ DB.getDB.then((DB) => {
return res.json(bibles); return res.json(bibles);
}); });
/**
* @swagger
* /bible/search:
* get:
* summary: Search the Bible
* tags: [Bible]
* security:
* - cookieAuth: []
* parameters:
* - in: query
* name: query
* required: true
* schema:
* type: string
* - in: query
* name: limit
* schema:
* type: integer
* default: 10
* - in: query
* name: bibleId
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/search", async (req, res) => { router.get("/search", async (req, res) => {
const query = req.query.query; const query = req.query.query;
const limit = req.query.limit || 10; const limit = req.query.limit || 10;

View File

@@ -39,6 +39,13 @@ DB.getDB.then((DB) => {
// }); // });
// }); // });
/**
* @swagger
* tags:
* name: Payments
* description: Payment processing
*/
let intent = async (req, res) => { let intent = async (req, res) => {
const userid = req.body.userid; const userid = req.body.userid;
const price = req.body.price || 500; const price = req.body.price || 500;
@@ -94,9 +101,76 @@ DB.getDB.then((DB) => {
}; };
/**
* @swagger
* /payments/create-payment-intent:
* post:
* summary: Creates a Stripe Payment Intent
* tags: [Payments]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* userid:
* type: string
* price:
* type: number
* description:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/create-payment-intent", intent); router.post("/create-payment-intent", intent);
/**
* @swagger
* /payments/intent:
* post:
* summary: Creates a Stripe Payment Intent (Alias for /create-payment-intent)
* tags: [Payments]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* userid:
* type: string
* price:
* type: number
* description:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/intent", intent); router.post("/intent", intent);
/**
* @swagger
* /payments/register:
* post:
* summary: Registers a payment after a successful Stripe transaction
* tags: [Payments]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* userid:
* type: string
* result:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/register", async (req, res) => { router.post("/register", async (req, res) => {
const userid = req.body.userid; const userid = req.body.userid;
const result = req.body.result; const result = req.body.result;

View File

@@ -77,6 +77,25 @@ DB.getDB.then((DB) => {
return mergedPosts; return mergedPosts;
}; };
/**
* @swagger
* tags:
* name: Posts
* description: Post management
*/
/**
* @swagger
* /post/organic:
* get:
* summary: Get the organic feed for the current user
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/organic", async (req, res) => { router.get("/organic", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
let organicPosts = await DB.getFeed(profileid); let organicPosts = await DB.getFeed(profileid);
@@ -86,6 +105,18 @@ DB.getDB.then((DB) => {
return res.json(posts); return res.json(posts);
}); });
/**
* @swagger
* /post:
* get:
* summary: Get the feed with promotional content
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/", async (req, res) => { router.get("/", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
//Add non-organic posts //Add non-organic posts
@@ -95,6 +126,26 @@ DB.getDB.then((DB) => {
return res.json(posts); return res.json(posts);
}); });
/**
* @swagger
* /post/tag/{tag}:
* get:
* summary: Get posts with a specific tag
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: tag
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
* 400:
* description: Tag is required
*/
router.get("/tag/:tag", async (req, res) => { router.get("/tag/:tag", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
const tag = req.query.tag || req.params.tag; const tag = req.query.tag || req.params.tag;
@@ -109,6 +160,24 @@ DB.getDB.then((DB) => {
return res.json(posts); return res.json(posts);
}); });
/**
* @swagger
* /post/usr/{id}:
* get:
* summary: Get posts from a specific user
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/usr/:id", async (req, res) => { router.get("/usr/:id", async (req, res) => {
const profileId = req.params.id; const profileId = req.params.id;
const viewerProdileId = getProfileId(req); const viewerProdileId = getProfileId(req);
@@ -124,6 +193,24 @@ DB.getDB.then((DB) => {
return res.json(posts); return res.json(posts);
}); });
/**
* @swagger
* /post/usr/{id}/images:
* get:
* summary: Get all image posts from a user
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/usr/:id/images", async (req, res) => { router.get("/usr/:id/images", async (req, res) => {
const profileid = req.params.id; const profileid = req.params.id;
const viewerProfileId = getProfileId(req); const viewerProfileId = getProfileId(req);
@@ -134,6 +221,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/usr/{id}/embedded:
* get:
* summary: Get all embedded posts from a user
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/usr/:id/embedded", async (req, res) => { router.get("/usr/:id/embedded", async (req, res) => {
const profileid = req.params.id; const profileid = req.params.id;
const viewerProfileId = getProfileId(req); const viewerProfileId = getProfileId(req);
@@ -144,6 +249,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/usr/{id}/media:
* get:
* summary: Get all media posts from a user
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/usr/:id/media", async (req, res) => { router.get("/usr/:id/media", async (req, res) => {
const profileid = req.params.id; const profileid = req.params.id;
const viewerProfileId = getProfileId(req); const viewerProfileId = getProfileId(req);
@@ -154,11 +277,49 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/video/{id}:
* get:
* summary: Get video details by ID
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/video/:id", async (req, res) => { router.get("/video/:id", async (req, res) => {
videoId = req.params.id; videoId = req.params.id;
return res.json([]); return res.json([]);
}); });
/**
* @swagger
* /post:
* post:
* summary: Create a new post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* responses:
* 200:
* description: OK
* 403:
* description: Not authorized to post to this group
*/
router.post("/", async (req, res) => { router.post("/", async (req, res) => {
let post = { let post = {
profileid: getProfileId(req), profileid: getProfileId(req),
@@ -198,6 +359,27 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/react:
* post:
* summary: React to a post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/react", async (req, res) => { router.post("/react", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -212,6 +394,27 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/unreact:
* post:
* summary: Remove a reaction from a post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/unreact", async (req, res) => { router.post("/unreact", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -221,6 +424,27 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/bookmark:
* post:
* summary: Bookmark a post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/bookmark", async (req, res) => { router.post("/bookmark", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -230,6 +454,27 @@ DB.getDB.then((DB) => {
}); });
}) })
/**
* @swagger
* /post/unbookmark:
* post:
* summary: Remove a bookmark from a post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/unbookmark", async (req, res) => { router.post("/unbookmark", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -239,6 +484,29 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/comment:
* post:
* summary: Add a comment to a post
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* content:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/comment/", async (req, res) => { router.post("/comment/", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -258,6 +526,30 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/comment/react:
* post:
* summary: React to a comment
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* commentDate:
* type: string
* format: date-time
* responses:
* 200:
* description: OK
*/
router.post("/comment/react", async (req, res) => { router.post("/comment/react", async (req, res) => {
let userid = getProfileId(req); let userid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -272,6 +564,30 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/comment/unreact:
* post:
* summary: Remove a reaction from a comment
* tags: [Posts]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* postid:
* type: string
* commentDate:
* type: string
* format: date-time
* responses:
* 200:
* description: OK
*/
router.post("/comment/unreact", async (req, res) => { router.post("/comment/unreact", async (req, res) => {
let profileid = getProfileId(req); let profileid = getProfileId(req);
let postid = req.body.postid; let postid = req.body.postid;
@@ -282,6 +598,18 @@ DB.getDB.then((DB) => {
}) })
}); });
/**
* @swagger
* /post/images:
* get:
* summary: Get all image posts for the current user
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/images", async (req, res) => { router.get("/images", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid); const posts = await DB.getMediaTagPostOfUser(profileid, profileid);
@@ -291,6 +619,18 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/embedded:
* get:
* summary: Get all embedded posts for the current user
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/embedded", async (req, res) => { router.get("/embedded", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@iframe:"); const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@iframe:");
@@ -300,6 +640,18 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/media:
* get:
* summary: Get all media posts for the current user
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/media", async (req, res) => { router.get("/media", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@youtube:|@vimeo:|@hls:"); const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@youtube:|@vimeo:|@hls:");
@@ -309,6 +661,18 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/course/recent:
* get:
* summary: Get recently watched media from courses
* tags: [Posts]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/course/recent", async (req, res) => { router.get("/course/recent", async (req, res) => {
const profileid = getProfileId(req); const profileid = getProfileId(req);
const profile = await DB.getProfileCache(profileid); const profile = await DB.getProfileCache(profileid);
@@ -356,6 +720,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /post/{id}:
* get:
* summary: Get a specific post by ID
* tags: [Posts]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/:id", async (req, res) => { router.get("/:id", async (req, res) => {
const postId = req.params.id; const postId = req.params.id;
const post = await DB.getPost(postId); const post = await DB.getPost(postId);

View File

@@ -14,6 +14,36 @@ DB.getDB.then((DB) => {
return profile.userid === String(userid); return profile.userid === String(userid);
} }
/**
* @swagger
* tags:
* name: Profiles
* description: User profile management
*/
/**
* @swagger
* /user/mine:
* get:
* summary: Get all profiles for the logged-in user
* tags: [Profiles]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: string
* profiles:
* type: array
* items:
* type: object
*/
router.get("/mine", async (req, res) => { router.get("/mine", async (req, res) => {
let userid = getUserId(req); let userid = getUserId(req);
let profiles = await DB.getUserProfiles(userid); let profiles = await DB.getUserProfiles(userid);
@@ -23,6 +53,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/new:
* get:
* summary: (DEPRECATED) Create a new profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: query
* name: content
* required: true
* schema:
* type: object
* responses:
* 200:
* description: OK
*/
router.get("/new", async (req, res) => { //Deprecated please use route post("/") router.get("/new", async (req, res) => { //Deprecated please use route post("/")
let profile = { let profile = {
userid: getUserId(req), userid: getUserId(req),
@@ -36,6 +84,27 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user:
* post:
* summary: Create a new profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* content:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/", async (req, res) => { router.post("/", async (req, res) => {
let profile = { let profile = {
userid: getUserId(req), userid: getUserId(req),
@@ -57,6 +126,32 @@ DB.getDB.then((DB) => {
}); });
/**
* @swagger
* /user/invite:
* post:
* summary: Invite a new user by email
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* name:
* type: string
* email:
* type: string
* format: email
* responses:
* 200:
* description: OK
* 400:
* description: Bad request
*/
router.post("/invite", async (req, res) => { router.post("/invite", async (req, res) => {
try { try {
const userid = getUserId(req); const userid = getUserId(req);
@@ -94,6 +189,25 @@ DB.getDB.then((DB) => {
} }
}); });
/**
* @swagger
* /user/invite/{email}:
* get:
* summary: Get invitation details for an email
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: email
* required: true
* schema:
* type: string
* format: email
* responses:
* 200:
* description: OK
*/
router.get("/invite/:email", async (req, res) => { router.get("/invite/:email", async (req, res) => {
const userid = getUserId(req); const userid = getUserId(req);
const email = req.params.email; const email = req.params.email;
@@ -106,6 +220,18 @@ DB.getDB.then((DB) => {
return res.json({ status: "ok", ...r }); return res.json({ status: "ok", ...r });
}); });
/**
* @swagger
* /user/groups:
* get:
* summary: Get a list of all groups
* tags: [Profiles]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/groups", async (req, res) => { router.get("/groups", async (req, res) => {
let groups = await DB.getGroups(); let groups = await DB.getGroups();
return res.json({ return res.json({
@@ -114,6 +240,18 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/following:
* get:
* summary: Get a list of groups the current profile is following
* tags: [Profiles]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/groups/following", async (req, res) => { router.get("/groups/following", async (req, res) => {
const profileId = getProfileId(req); const profileId = getProfileId(req);
let groups = await DB.getFollowingGroups(profileId); let groups = await DB.getFollowingGroups(profileId);
@@ -123,6 +261,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups:
* post:
* summary: Create a new group
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/groups", async (req, res) => { router.post("/groups", async (req, res) => {
let profile = { let profile = {
userid: getUserId(req), userid: getUserId(req),
@@ -137,6 +293,18 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/courses:
* get:
* summary: Get a list of all courses
* tags: [Profiles]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/courses", async (req, res) => { router.get("/courses", async (req, res) => {
let groups = await DB.getCourses(); let groups = await DB.getCourses();
return res.json({ return res.json({
@@ -145,6 +313,29 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/accept:
* post:
* summary: Accept a request to join a private group
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* groupid:
* type: string
* profileid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/groups/accept", async (req, res) => { router.post("/groups/accept", async (req, res) => {
//This function should be called to accept the join request //This function should be called to accept the join request
//of an user that attempt to join a private group. //of an user that attempt to join a private group.
@@ -164,6 +355,29 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/reject:
* post:
* summary: Reject a request to join a private group
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* groupid:
* type: string
* profileid:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/groups/reject", async (req, res) => { router.post("/groups/reject", async (req, res) => {
//This function should be called to reject the join request //This function should be called to reject the join request
//of an user that attempt to join a private group. //of an user that attempt to join a private group.
@@ -183,6 +397,28 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/search:
* get:
* summary: Search for groups
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: query
* name: query
* required: true
* schema:
* type: string
* - in: query
* name: courses
* schema:
* type: boolean
* responses:
* 200:
* description: OK
*/
router.get("/groups/search", async (req, res) => { router.get("/groups/search", async (req, res) => {
let query = req.query.query; let query = req.query.query;
let coursesB = req.query.courses ? true : false; let coursesB = req.query.courses ? true : false;
@@ -193,6 +429,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/{id}:
* get:
* summary: Get details for a specific group
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/groups/:id", async (req, res) => { router.get("/groups/:id", async (req, res) => {
const groupid = req.params.id; const groupid = req.params.id;
let groups = await DB.getGroup(groupid); let groups = await DB.getGroup(groupid);
@@ -202,6 +456,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/{id}/subscribe:
* get:
* summary: Subscribe to a group
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/groups/:id/subscribe", async (req, res) => { router.get("/groups/:id/subscribe", async (req, res) => {
const groupid = req.params.id; const groupid = req.params.id;
const profileid = getProfileId(req); const profileid = getProfileId(req);
@@ -214,6 +486,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/groups/{id}/unsubscribe:
* get:
* summary: Unsubscribe from a group
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/groups/:id/unsubscribe", async (req, res) => { router.get("/groups/:id/unsubscribe", async (req, res) => {
const groupid = req.params.id; const groupid = req.params.id;
const profileid = getProfileId(req); const profileid = getProfileId(req);
@@ -224,6 +514,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/search:
* get:
* summary: Search for profiles
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: query
* name: query
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/search", async (req, res) => { router.get("/search", async (req, res) => {
let query = req.query.query; let query = req.query.query;
let profiles = await DB.searchProfile(query); let profiles = await DB.searchProfile(query);
@@ -233,6 +541,29 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/setData:
* post:
* summary: Set custom data for a profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* key:
* type: string
* value:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/setData", (req, res) => { router.post("/setData", (req, res) => {
const key = req.body.key; const key = req.body.key;
const value = req.body.value; const value = req.body.value;
@@ -243,6 +574,29 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/myProfile:
* post:
* summary: Update the current user's profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* profile:
* type: object
* data:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/myProfile", async (req, res) => { router.post("/myProfile", async (req, res) => {
let profile = { let profile = {
userid: getUserId(req), userid: getUserId(req),
@@ -256,6 +610,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/{id}:
* get:
* summary: Get a specific profile by ID
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/:id", async (req, res) => { router.get("/:id", async (req, res) => {
let profileId = req.params.id; let profileId = req.params.id;
let profile = await DB.getProfile(profileId); let profile = await DB.getProfile(profileId);
@@ -265,6 +637,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/{id}:
* delete:
* summary: Delete a profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.delete("/:id", async (req, res) => { router.delete("/:id", async (req, res) => {
const profileId = req.params.id; const profileId = req.params.id;
const userid = getUserId(req); const userid = getUserId(req);
@@ -278,6 +668,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/{id}/follow:
* get:
* summary: Follow a profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/:id/follow", async (req, res) => { router.get("/:id/follow", async (req, res) => {
let followProfileId = req.params.id; let followProfileId = req.params.id;
const profileid = getProfileId(req); const profileid = getProfileId(req);
@@ -288,6 +696,24 @@ DB.getDB.then((DB) => {
}); });
}); });
/**
* @swagger
* /user/{id}/unfollow:
* get:
* summary: Unfollow a profile
* tags: [Profiles]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/:id/unfollow", async (req, res) => { router.get("/:id/unfollow", async (req, res) => {
let followProfileId = req.params.id; let followProfileId = req.params.id;
const profileid = getProfileId(req); const profileid = getProfileId(req);

View File

@@ -15,6 +15,25 @@ DB.getDB.then((DB)=>{
return DB.ObjectID(req.cookies.profile_id || req.query.profile_id || req.body.profile_id); return DB.ObjectID(req.cookies.profile_id || req.query.profile_id || req.body.profile_id);
} }
/**
* @swagger
* tags:
* name: Songs
* description: Song management
*/
/**
* @swagger
* /songs:
* get:
* summary: Get all songs
* tags: [Songs]
* security:
* - cookieAuth: []
* responses:
* 200:
* description: OK
*/
router.get("/", async (req, res) => { router.get("/", async (req, res) => {
let profileId = req.params.id; let profileId = req.params.id;
let songs = await DB.getSongs(); let songs = await DB.getSongs();
@@ -24,6 +43,24 @@ DB.getDB.then((DB)=>{
}); });
}); });
/**
* @swagger
* /songs:
* post:
* summary: Create a new song
* tags: [Songs]
* security:
* - cookieAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* responses:
* 200:
* description: OK
*/
router.post("/", async (req, res) => { router.post("/", async (req, res) => {
let post = { let post = {
userid: getUserId(req), userid: getUserId(req),
@@ -39,6 +76,24 @@ DB.getDB.then((DB)=>{
}) })
}); });
/**
* @swagger
* /songs/{id}:
* get:
* summary: Get a specific song by ID
* tags: [Songs]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/:id", async (req, res) => { router.get("/:id", async (req, res) => {
let profileId = req.params.id; let profileId = req.params.id;
let profile = await DB.getProfile(profileId); let profile = await DB.getProfile(profileId);
@@ -53,6 +108,24 @@ DB.getDB.then((DB)=>{
return true; return true;
} }
/**
* @swagger
* /songs/{id}:
* delete:
* summary: Delete a song
* tags: [Songs]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.delete("/:id", async (req, res) => { router.delete("/:id", async (req, res) => {
const userid = getUserId(req); const userid = getUserId(req);
const songId = req.params.id; const songId = req.params.id;
@@ -66,6 +139,33 @@ DB.getDB.then((DB)=>{
}); });
}); });
/**
* @swagger
* /songs/{id}:
* post:
* summary: Update a song
* tags: [Songs]
* security:
* - cookieAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: string
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* content:
* type: string
* responses:
* 200:
* description: OK
*/
router.post("/:id", async (req, res) => { router.post("/:id", async (req, res) => {
const userid = getUserId(req); const userid = getUserId(req);
const songId = req.params.id; const songId = req.params.id;

View File

@@ -67,12 +67,51 @@ const getMedia = async (eventId) => {
}; };
//getMedia('y42zyf3').then(console.log) //getMedia('y42zyf3').then(console.log)
/**
* @swagger
* tags:
* name: Subsplash
* description: Subsplash API integration
*/
DB.getDB.then((DB) => { DB.getDB.then((DB) => {
/**
* @swagger
* /subsplash/events/{calendarId}:
* get:
* summary: Get events from a Subsplash calendar
* tags: [Subsplash]
* parameters:
* - in: path
* name: calendarId
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/events/:calendarId", async (req, res) => { router.get("/events/:calendarId", async (req, res) => {
const events = await getEvents(req.params.calendarId) const events = await getEvents(req.params.calendarId)
return res.json(events); return res.json(events);
}); });
/**
* @swagger
* /subsplash/media/{seriesId}:
* get:
* summary: Get media from a Subsplash media series
* tags: [Subsplash]
* parameters:
* - in: path
* name: seriesId
* required: true
* schema:
* type: string
* responses:
* 200:
* description: OK
*/
router.get("/media/:seriesId", async (req, res) => { router.get("/media/:seriesId", async (req, res) => {
const events = await getMedia(req.params.seriesId) const events = await getMedia(req.params.seriesId)
return res.json(events); return res.json(events);