Add swagger API
This commit is contained in:
parent
ad746af295
commit
b92468f29b
30
app.js
30
app.js
@ -4,6 +4,34 @@ const Knex = require('knex');
|
||||
const cron = require('node-cron');
|
||||
const knexConfig = require('./src/config/database');
|
||||
const MessageService = require('./src/email_server/services/MessageService');
|
||||
const swaggerJsdoc = require('swagger-jsdoc');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
|
||||
const swaggerOptions = {
|
||||
definition: {
|
||||
openapi: '3.1.0',
|
||||
info: {
|
||||
title: '2weekmail API',
|
||||
version: '1.0.0',
|
||||
description: 'Documentation for the 2weekmail API',
|
||||
},
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
}
|
||||
],
|
||||
servers: [
|
||||
{
|
||||
url: 'https://2weekmail.fyi',
|
||||
description: 'Production server',
|
||||
},
|
||||
],
|
||||
},
|
||||
apis: ['./src/routes/*.js'],
|
||||
};
|
||||
|
||||
const swaggerSpec = swaggerJsdoc(swaggerOptions);
|
||||
|
||||
|
||||
// Initialize Knex
|
||||
const knex = Knex(knexConfig.development);
|
||||
@ -19,6 +47,8 @@ app.use('/messages', require('./src/routes/messages'));
|
||||
app.use('/email', require('./src/routes/email'));
|
||||
app.use('/test', require('./src/routes/test'));
|
||||
app.use('/', require('./src/routes/index'));
|
||||
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
||||
|
||||
|
||||
// Schedule cleanup job
|
||||
cron.schedule('0 0 * * *', async () => {
|
||||
|
||||
271
package-lock.json
generated
271
package-lock.json
generated
@ -18,9 +18,61 @@
|
||||
"mysql2": "^3.12.0",
|
||||
"node-cron": "^3.0.3",
|
||||
"objection": "^3.1.5",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"unique-names-generator": "^4.7.1"
|
||||
}
|
||||
},
|
||||
"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/@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": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
|
||||
@ -41,6 +93,19 @@
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"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/@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/abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
@ -157,6 +222,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
@ -270,6 +341,12 @@
|
||||
"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/chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
@ -409,6 +486,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"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/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
@ -507,6 +596,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
@ -940,6 +1038,18 @@
|
||||
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
@ -1075,6 +1185,13 @@
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"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.includes": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||
@ -1087,6 +1204,13 @@
|
||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||
"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.isinteger": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||
@ -1111,6 +1235,12 @@
|
||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||
"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/lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
@ -1490,6 +1620,13 @@
|
||||
"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/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
@ -1910,6 +2047,92 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"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/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/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.18.2",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz",
|
||||
"integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==",
|
||||
"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": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||
@ -2015,6 +2238,15 @@
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.12.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz",
|
||||
"integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
@ -2060,6 +2292,45 @@
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"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/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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
"mysql2": "^3.12.0",
|
||||
"node-cron": "^3.0.3",
|
||||
"objection": "^3.1.5",
|
||||
"swagger-jsdoc": "^6.2.8",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"unique-names-generator": "^4.7.1"
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,23 +4,29 @@ const Knex = require('knex');
|
||||
const knexConfig = require('../src/config/database');
|
||||
const knex = Knex(knexConfig.development);
|
||||
Model.knex(knex);
|
||||
const crypto = require('crypto');
|
||||
|
||||
const email = process.argv[2];
|
||||
const password = process.argv[3];
|
||||
let password = process.argv[3];
|
||||
const isAdmin = process.argv[4] === 'true';
|
||||
|
||||
if (!email || !password) {
|
||||
console.error('Usage: node make_user.js <email> <password> [isAdmin]');
|
||||
if (!email && !password) {
|
||||
console.error('Usage: node make_user.js <email> [password] [isAdmin]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!password) {
|
||||
password = crypto.randomBytes(16).toString('hex');
|
||||
}
|
||||
|
||||
const user = await User.query().insert({
|
||||
email: email,
|
||||
password: password,
|
||||
is_admin: isAdmin
|
||||
});
|
||||
console.log(`User created: ${user.email}`);
|
||||
console.log(`Password: ${password}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
41
scripts/update_admin_password.js
Normal file
41
scripts/update_admin_password.js
Normal file
@ -0,0 +1,41 @@
|
||||
const User = require('../src/db/models/User');
|
||||
const { Model } = require('objection');
|
||||
const Knex = require('knex');
|
||||
const knexConfig = require('../src/config/database');
|
||||
const knex = Knex(knexConfig.development);
|
||||
Model.knex(knex);
|
||||
const crypto = require('crypto');
|
||||
|
||||
const email = process.argv[2];
|
||||
let password = process.argv[3];
|
||||
|
||||
if (!email && !password) {
|
||||
console.error('Usage: node update_admin_password.js <email> [password]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const user = await User.query().where('email', email).first();
|
||||
if (!user) {
|
||||
console.error('User not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!user.is_admin) {
|
||||
console.error('User is not an admin');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
password = crypto.randomBytes(16).toString('hex');
|
||||
}
|
||||
|
||||
user.password = password;
|
||||
|
||||
await user.$query().patch();
|
||||
console.log(`User password updated: ${user.email}`);
|
||||
console.log(`New password: ${password}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
main();
|
||||
@ -1,14 +1,15 @@
|
||||
const express = require('express');
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const jwt = require('jsonwebtoken');
|
||||
const User = require('../db/models/User');
|
||||
const config = require('../config/haraka');
|
||||
|
||||
const jwt = require("jsonwebtoken");
|
||||
const User = require("../db/models/User");
|
||||
const config = require("../config/haraka");
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/login:
|
||||
* post:
|
||||
* tags:
|
||||
* - Authentication
|
||||
* summary: Login and get API key
|
||||
* description: Login with email and password to get an API key
|
||||
* requestBody:
|
||||
@ -17,23 +18,43 @@ const config = require('../config/haraka');
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - email
|
||||
* - password
|
||||
* properties:
|
||||
* email:
|
||||
* type: string
|
||||
* format: email
|
||||
* description: User's email
|
||||
* example: user@example.com
|
||||
* password:
|
||||
* type: string
|
||||
* format: password
|
||||
* description: User's password
|
||||
* example: password123
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Successful login
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* token:
|
||||
* type: string
|
||||
* description: API key for authentication
|
||||
* 401:
|
||||
* description: Invalid credentials
|
||||
* 422:
|
||||
* description: Validation error
|
||||
*/
|
||||
router.post('/login', async (req, res) => {
|
||||
router.post("/login", async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
const user = await User.query().where('email', email).first();
|
||||
const user = await User.query().where("email", email).first();
|
||||
|
||||
if (!user || !(await user.verifyPassword(password))) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
return res.status(401).json({ error: "Invalid credentials" });
|
||||
}
|
||||
|
||||
const generateToken = () => {
|
||||
@ -45,8 +66,8 @@ router.post('/login', async (req, res) => {
|
||||
};
|
||||
|
||||
let currentToken = await User.query()
|
||||
.select('api_key')
|
||||
.where('id', user.id)
|
||||
.select("api_key")
|
||||
.where("id", user.id)
|
||||
.first();
|
||||
|
||||
let token;
|
||||
@ -57,20 +78,16 @@ router.post('/login', async (req, res) => {
|
||||
token = currentToken.api_key;
|
||||
} catch (tokenError) {
|
||||
token = generateToken();
|
||||
await User.query()
|
||||
.where('id', user.id)
|
||||
.update({ api_key: token });
|
||||
await User.query().where("id", user.id).update({ api_key: token });
|
||||
}
|
||||
} else {
|
||||
token = generateToken();
|
||||
await User.query()
|
||||
.where('id', user.id)
|
||||
.update({ api_key: token });
|
||||
await User.query().where("id", user.id).update({ api_key: token });
|
||||
}
|
||||
|
||||
res.json({ token });
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
console.error("Login error:", error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
@ -35,10 +35,38 @@ function generateUniqueName() {
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* TempEmail:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* description: The temporary email ID
|
||||
* email:
|
||||
* type: string
|
||||
* description: The generated email address
|
||||
* user_id:
|
||||
* type: integer
|
||||
* description: ID of the user who owns this email
|
||||
* expires_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: Expiration date of the temporary email
|
||||
* securitySchemes:
|
||||
* bearerAuth:
|
||||
* type: http
|
||||
* scheme: bearer
|
||||
* bearerFormat: JWT
|
||||
*
|
||||
* /email/generate:
|
||||
* post:
|
||||
* tags:
|
||||
* - Temporary Email
|
||||
* summary: Generate a temporary email
|
||||
* description: Generate a temporary email with a random domain
|
||||
* description: Generate a temporary email with a random domain. The email will expire after 14 days.
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: false
|
||||
* content:
|
||||
@ -48,7 +76,91 @@ function generateUniqueName() {
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* description: Name for the temporary email
|
||||
* description: Custom name for the temporary email (optional)
|
||||
* example: john-doe
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Temporary email successfully generated
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/TempEmail'
|
||||
* 401:
|
||||
* description: Unauthorized - Invalid or missing authentication token
|
||||
* 500:
|
||||
* description: Server error while generating email
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
*
|
||||
* /email/list:
|
||||
* get:
|
||||
* tags:
|
||||
* - Temporary Email
|
||||
* summary: List all temporary emails
|
||||
* description: Get a list of all temporary emails for the authenticated user
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of temporary emails
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/TempEmail'
|
||||
* 401:
|
||||
* description: Unauthorized - Invalid or missing authentication token
|
||||
*
|
||||
* /email/delete/{id}:
|
||||
* delete:
|
||||
* tags:
|
||||
* - Temporary Email
|
||||
* summary: Delete a temporary email
|
||||
* description: Delete a temporary email by its ID. Only the owner can delete their emails.
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the temporary email to delete
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Email successfully deleted
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: success
|
||||
* message:
|
||||
* type: string
|
||||
* example: Temp email deleted
|
||||
* 401:
|
||||
* description: Unauthorized - Invalid or missing authentication token
|
||||
* 404:
|
||||
* description: Temporary email not found or doesn't belong to user
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* status:
|
||||
* type: string
|
||||
* example: error
|
||||
* message:
|
||||
* type: string
|
||||
* example: Temp email not found
|
||||
*/
|
||||
router.post('/generate', async (req, res) => {
|
||||
try {
|
||||
@ -76,30 +188,12 @@ router.post('/generate', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /email/list:
|
||||
* get:
|
||||
* summary: List all temporary emails
|
||||
* description: Get a list of all temporary emails for the authenticated user
|
||||
*/
|
||||
|
||||
router.get('/list', async (req, res) => {
|
||||
const tempEmails = await TempEmail.query().where('user_id', req.user.id);
|
||||
res.json(tempEmails);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /email/delete/{id}:
|
||||
* delete:
|
||||
* summary: Delete a temporary email
|
||||
* description: Delete a temporary email by its ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* description: ID of the temporary email to delete
|
||||
*/
|
||||
router.delete('/delete/:id', async (req, res) => {
|
||||
const tempEmail = await TempEmail.query().where('id', req.params.id).andWhere('user_id', req.user.id).delete();
|
||||
if (!tempEmail) {
|
||||
|
||||
@ -2,7 +2,7 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', async (req, res) => {
|
||||
res.json({ message: 'Hello World' });
|
||||
res.send(`<h3>2weekmail API</h3><a href="/docs">API Documentation</a>`);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@ -7,43 +7,130 @@ router.use(authenticateToken);
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* components:
|
||||
* schemas:
|
||||
* Message:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* description: The message ID
|
||||
* temp_email_id:
|
||||
* type: integer
|
||||
* description: ID of the temporary email that received this message
|
||||
* subject:
|
||||
* type: string
|
||||
* description: Email subject
|
||||
* sender:
|
||||
* type: string
|
||||
* description: Sender's email address
|
||||
* content:
|
||||
* type: string
|
||||
* description: Message content
|
||||
* created_at:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: Message creation timestamp
|
||||
* example:
|
||||
* id: 1
|
||||
* temp_email_id: 123
|
||||
* subject: "Welcome to our service"
|
||||
* sender: "no-reply@example.com"
|
||||
* content: "Hello, this is a test message..."
|
||||
* created_at: "2024-01-27T12:00:00Z"
|
||||
*
|
||||
* /messages/list:
|
||||
* post:
|
||||
* summary: List messages
|
||||
* description: List messages based on query parameters
|
||||
* tags:
|
||||
* - Messages
|
||||
* summary: List messages for a temporary email
|
||||
* description: Retrieve all messages received by a specific temporary email address
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - temp_email_id
|
||||
* properties:
|
||||
* temp_email_id:
|
||||
* type: string
|
||||
* type: integer
|
||||
* description: ID of the temporary email
|
||||
* example: 123
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of messages successfully retrieved
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/Message'
|
||||
* 401:
|
||||
* description: Unauthorized - Invalid or missing authentication token
|
||||
* 404:
|
||||
* description: Temporary email not found
|
||||
* 500:
|
||||
* description: Server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
*
|
||||
* /messages/read/{id}:
|
||||
* post:
|
||||
* tags:
|
||||
* - Messages
|
||||
* summary: Get a specific message
|
||||
* description: Retrieve a single message by its ID with associated temporary email details
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: ID of the message to retrieve
|
||||
* example: 1
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Message successfully retrieved
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* allOf:
|
||||
* - $ref: '#/components/schemas/Message'
|
||||
* - type: object
|
||||
* properties:
|
||||
* temp_email:
|
||||
* $ref: '#/components/schemas/TempEmail'
|
||||
* 401:
|
||||
* description: Unauthorized - Invalid or missing authentication token
|
||||
* 404:
|
||||
* description: Message not found
|
||||
* 500:
|
||||
* description: Server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* error:
|
||||
* type: string
|
||||
*/
|
||||
router.post('/list', async (req, res) => {
|
||||
const messages = await Message.query().where('temp_email_id', req.body.temp_email_id);
|
||||
res.json(messages);
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /messages/read/{id}:
|
||||
* post:
|
||||
* summary: Get a message by ID
|
||||
* description: Get a message by its ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: string
|
||||
* description: ID of the message to read
|
||||
*/
|
||||
router.post('/read/:id', async (req, res) => {
|
||||
const message = await Message.query().where('id', req.body.id).withGraphFetched('temp_email').first();
|
||||
res.json(message);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user