init
This commit is contained in:
parent
10dc3e5ffe
commit
ef35a8aa6c
26
.eslintrc.js
Normal file
26
.eslintrc.js
Normal file
@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: 'eslint:recommended',
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'no-useless-escape': 0,
|
||||
'no-empty': ['warn'],
|
||||
},
|
||||
globals: {
|
||||
process: true,
|
||||
},
|
||||
}
|
3542
package-lock.json
generated
Normal file
3542
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
package.json
Normal file
37
package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "manager-bh",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"eslint": "eslint .",
|
||||
"start": "cross-env NODE_ENV=\"development\" nodemon ./server/index.js",
|
||||
"start:prod": "cross-env NODE_ENV=\"production\" nodemon ./server/index.js",
|
||||
"up:prod": "cross-env NODE_ENV=\"production\" node ./server/index.js",
|
||||
"deploy:d:stop": "docker compose down",
|
||||
"deploy:d:build": "docker compose build",
|
||||
"deploy:d:up": "docker compose up -d",
|
||||
"redeploy": "npm run deploy:d:build && npm run deploy:d:stop && npm run deploy:d:up"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.17.6",
|
||||
"eslint": "^7.30.0",
|
||||
"nodemon": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@brojs/mailer": "^1.4.0-alpha.0",
|
||||
"@keycloak/keycloak-admin-client": "^26.0.5",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^5.0.1",
|
||||
"express-session": "^1.18.1",
|
||||
"js-sha256": "^0.11.0",
|
||||
"keycloak-connect": "^26.0.5",
|
||||
"uuid": "^11.0.2"
|
||||
}
|
||||
}
|
27
postman/manager.postman_collection.json
Normal file
27
postman/manager.postman_collection.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "64d9b604-a7c8-46b3-bd31-8249649ec269",
|
||||
"name": "manager",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "26924638"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "healthcheck",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "{{host}}/healthcheck",
|
||||
"host": [
|
||||
"{{host}}"
|
||||
],
|
||||
"path": [
|
||||
"healthcheck"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
8
server/.serverrc.js
Normal file
8
server/.serverrc.js
Normal file
@ -0,0 +1,8 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
dataPath: path.resolve(__dirname, 'data'),
|
||||
maxLogCount: 3,
|
||||
mailStepTimer: 3000,
|
||||
protocol: 'http',
|
||||
}
|
40
server/_helpers/authorize.js
Normal file
40
server/_helpers/authorize.js
Normal file
@ -0,0 +1,40 @@
|
||||
const assignParam = (dev, prod) =>
|
||||
process.env.NODE_ENV !== 'production' ? dev : prod
|
||||
|
||||
const parseToken = (req, res, next) => {
|
||||
req.isAdmin = assignParam(
|
||||
true,
|
||||
Boolean(
|
||||
req?.kauth?.grant?.access_token?.content?.resource_access?.[
|
||||
'manager-admin'
|
||||
]?.roles?.includes('manager_admin'),
|
||||
),
|
||||
)
|
||||
|
||||
req.userId = assignParam(
|
||||
process.env['KC.DEV.ID'],
|
||||
req.kauth?.grant?.access_token?.content?.sub,
|
||||
)
|
||||
req.user = assignParam(
|
||||
{ sub: '123', name: 'dev' },
|
||||
req.kauth?.grant?.access_token?.content,
|
||||
)
|
||||
|
||||
next()
|
||||
}
|
||||
|
||||
const adminOnly = [
|
||||
parseToken,
|
||||
(req, res, next) => {
|
||||
if (!req.isAdmin) {
|
||||
// user's role is not authorized
|
||||
return res.status(403).send({ code: 4, error: 'Access denied' })
|
||||
}
|
||||
next()
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
adminOnly,
|
||||
parseToken,
|
||||
}
|
18
server/_helpers/error-handler.js
Normal file
18
server/_helpers/error-handler.js
Normal file
@ -0,0 +1,18 @@
|
||||
const { getAnswer } = require('../utils/common');
|
||||
|
||||
function errorHandler(err, req, res, _next) {
|
||||
console.error(err);
|
||||
if (typeof (err) === 'string') {
|
||||
return res.status(400).json(getAnswer([{ message: err }]));
|
||||
}
|
||||
|
||||
if (err.name === 'UnauthorizedError') {
|
||||
// jwt authentication error
|
||||
return res.status(401).json(getAnswer([{ message: 'Invalid Token' }]));
|
||||
}
|
||||
|
||||
// default to 500 server error
|
||||
return res.status(500).json(getAnswer([{ message: err?.message || 'Invalid Token' }]));
|
||||
}
|
||||
|
||||
module.exports = errorHandler;
|
36
server/index.js
Normal file
36
server/index.js
Normal file
@ -0,0 +1,36 @@
|
||||
const express = require("express");
|
||||
const bodyParser = require("body-parser");
|
||||
const cookieParser = require("cookie-parser");
|
||||
const session = require("express-session");
|
||||
const app = express();
|
||||
require("dotenv").config();
|
||||
require("./mailer");
|
||||
|
||||
const errorHandler = require("./_helpers/error-handler");
|
||||
|
||||
const { keycloak } = require("./kc");
|
||||
|
||||
app.use(
|
||||
process.env.NODE_ENV !== "production"
|
||||
? (_, __, next) => next()
|
||||
: keycloak.middleware()
|
||||
);
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(
|
||||
session({ secret: "so secret", resave: true, saveUninitialized: true })
|
||||
);
|
||||
|
||||
app.use('/api', require('./routes'));
|
||||
|
||||
|
||||
app.use(bodyParser.json({ limit: "50mb" }));
|
||||
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
|
||||
|
||||
app.use(errorHandler);
|
||||
|
||||
app.listen(process.env.MANAGER_PORT, () =>
|
||||
console.log(`Listening on http://localhost:${process.env.MANAGER_PORT}`)
|
||||
);
|
||||
|
||||
module.exports = app;
|
39
server/kc.js
Normal file
39
server/kc.js
Normal file
@ -0,0 +1,39 @@
|
||||
const Keycloak = require("keycloak-connect");
|
||||
|
||||
const keycloak = new Keycloak(
|
||||
{},
|
||||
{
|
||||
clientId: "microfrontend-admin",
|
||||
bearerOnly: true,
|
||||
serverUrl: "https://kc.bro-js.ru",
|
||||
realm: "bro-js",
|
||||
}
|
||||
);
|
||||
|
||||
const kcAdminClientPromise = import("@keycloak/keycloak-admin-client")
|
||||
.then(
|
||||
async ({ default: KcAdminClient }) =>
|
||||
new KcAdminClient({
|
||||
baseUrl: "https://kc.bro-js.ru",
|
||||
realmName: "bro-js",
|
||||
})
|
||||
)
|
||||
.then(async (kcAdminClient) => {
|
||||
const credentials = {
|
||||
username: process.env['KC.TUZ.USERNAME'],
|
||||
password: process.env['KC.TUZ.PASSWORD'],
|
||||
grant_type: "password",
|
||||
grantType: "password",
|
||||
clientId: "microfrontend-admin",
|
||||
}
|
||||
await kcAdminClient.auth(credentials);
|
||||
|
||||
setInterval(() => kcAdminClient.auth(credentials), 3 * 24 * 60 *60 * 1000);
|
||||
|
||||
return kcAdminClient;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
keycloak,
|
||||
kcAdminClientPromise,
|
||||
}
|
16
server/mailer.js
Normal file
16
server/mailer.js
Normal file
@ -0,0 +1,16 @@
|
||||
const { AdminNotificationRequest, addToQueue, configs, init } = require('@brojs/mailer');
|
||||
|
||||
const rc = require('./.serverrc');
|
||||
const pkg = require('../package');
|
||||
|
||||
init({
|
||||
userName: process.env.SMTP_MAIL_LOGIN,
|
||||
password: process.env.SMTP_MAIL_PASSWORD,
|
||||
adminMails: process.env.MAIL_TO_1,
|
||||
smtpConfig: configs.yandex,
|
||||
queTimer: rc.mailStepTimer,
|
||||
});
|
||||
|
||||
if (process.env.MAIL_TO_1 && process.env.NODE_ENV === 'production') {
|
||||
addToQueue(new AdminNotificationRequest(`Деплой kc админки v${pkg.version} прошёл успешно (${process.env.ADMIN_FRONT_BASE_NAME}) (Время ${new Date().toLocaleString()})`));
|
||||
}
|
8
server/routes/index.js
Normal file
8
server/routes/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
const router = require('express').Router();
|
||||
const pkg = require('../../package.json')
|
||||
|
||||
router.get('/healthcheck', (req, res) => {
|
||||
res.send({ ok: true, version: pkg.version })
|
||||
})
|
||||
|
||||
module.exports = router;
|
22
server/utils/common.js
Normal file
22
server/utils/common.js
Normal file
@ -0,0 +1,22 @@
|
||||
const getAnswer = (error, body = null, success = true) => {
|
||||
if (error) {
|
||||
return { success: false, error, body }
|
||||
} else {
|
||||
return { success, body }
|
||||
}
|
||||
}
|
||||
|
||||
function cleanId(entity) {
|
||||
if (Array.isArray(entity)) {
|
||||
return entity.map(cleanId)
|
||||
}
|
||||
|
||||
const { _id, ...other } = entity;
|
||||
|
||||
return { ...other, id: _id };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAnswer,
|
||||
cleanId,
|
||||
}
|
Loading…
Reference in New Issue
Block a user