mirror of https://github.com/itsmrval/accessGate
admin dashboard, database updated (members, groups), group setup and permissions
parent
14dad1f5f1
commit
a3b8a865fd
37
index.js
37
index.js
|
|
@ -3,6 +3,13 @@ const express = require("express");
|
|||
const app = express();
|
||||
const session = require('express-session');
|
||||
const databaseService = require('./services/database.service');
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
const groupService = require("./services/group.service");
|
||||
|
||||
const User = require('./model/user.model')
|
||||
const Key = require('./model/key.model')
|
||||
const {makeAdmin} = require("./services/users.service");
|
||||
|
||||
databaseService.sync().then(() => {
|
||||
console.log("Database ready");
|
||||
|
|
@ -11,6 +18,11 @@ databaseService.sync().then(() => {
|
|||
|
||||
require('dotenv').config()
|
||||
|
||||
app.use(bodyParser.urlencoded({ extended: false }))
|
||||
|
||||
// parse application/json
|
||||
app.use(bodyParser.json())
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: process.env.SESSION_SECRET,
|
||||
|
|
@ -19,10 +31,22 @@ app.use(
|
|||
})
|
||||
);
|
||||
|
||||
|
||||
app.set('trust proxy', 1)
|
||||
app.set('view engine', 'ejs');
|
||||
app.use('/static', express.static('public'));
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
if (req.session.loggedin === true) {
|
||||
User.findOne({ where: { id: req.session.user.id } }).then((result) => {
|
||||
res.locals.session_user = result
|
||||
next()
|
||||
});
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/", (req, res) => {
|
||||
if (req.session.loggedin === true) {
|
||||
res.render('index', { user: req.session.user })
|
||||
|
|
@ -31,17 +55,20 @@ app.get("/", (req, res) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
app.get("/login", (req, res) => {
|
||||
res.render('login')
|
||||
});
|
||||
|
||||
app.get("/keys", (req, res) => {
|
||||
res.render('keys')
|
||||
});
|
||||
|
||||
var auth_route = require('./routes/auth.route');
|
||||
|
||||
app.use('/auth/', auth_route);
|
||||
|
||||
|
||||
|
||||
|
||||
app.use('/admin/', require('./routes/admin.route'));
|
||||
app.use('/auth/', require('./routes/auth.route'));
|
||||
app.use('/keys/', require('./routes/keys.route'));
|
||||
|
||||
app.listen(8080, () => {
|
||||
console.log("running");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
const { Model, DataTypes} = require('sequelize');
|
||||
const sequelize = require('../services/database.service');
|
||||
|
||||
class Group extends Model {}
|
||||
|
||||
Group.init({
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
primaryKey: true,
|
||||
required: true,
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'group'
|
||||
})
|
||||
|
||||
module.exports = Group;
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const { Model, DataTypes} = require('sequelize');
|
||||
const sequelize = require('../services/database.service');
|
||||
|
||||
class Key extends Model {}
|
||||
|
||||
Key.init({
|
||||
idKey: {
|
||||
type: DataTypes.STRING,
|
||||
primaryKey: true,
|
||||
required: true,
|
||||
},
|
||||
idOwner: {
|
||||
type: DataTypes.INTEGER,
|
||||
required: true,
|
||||
},
|
||||
content: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
},
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'key'
|
||||
})
|
||||
|
||||
module.exports = Key;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
const { Model, DataTypes} = require('sequelize');
|
||||
const sequelize = require('../services/database.service');
|
||||
|
||||
class Member extends Model {}
|
||||
|
||||
Member.init({
|
||||
groupName: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
},
|
||||
userId: {
|
||||
type: DataTypes.INTEGER,
|
||||
required: true,
|
||||
},
|
||||
role: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
defaultValue: 'member'
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'member'
|
||||
})
|
||||
|
||||
module.exports = Member;
|
||||
|
|
@ -7,16 +7,25 @@ User.init({
|
|||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
required: true,
|
||||
},
|
||||
admin: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
required: true,
|
||||
},
|
||||
login: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
},
|
||||
avatar: {
|
||||
type: DataTypes.STRING,
|
||||
required: true,
|
||||
},
|
||||
displayName: {
|
||||
type: DataTypes.STRING,
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
}, {
|
||||
sequelize,
|
||||
modelName: 'user'
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"axios": "^1.5.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"ejs": "^3.1.9",
|
||||
"express": "^4.18.2",
|
||||
|
|
@ -253,12 +254,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
|
|
@ -266,7 +267,7 @@
|
|||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
|
|
@ -652,6 +653,43 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/filelist": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||
|
|
@ -1671,9 +1709,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"homepage": "https://github.com/itsmrval/accessgate#readme",
|
||||
"dependencies": {
|
||||
"axios": "^1.5.0",
|
||||
"body-parser": "^1.20.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"ejs": "^3.1.9",
|
||||
"express": "^4.18.2",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
const express = require('express');
|
||||
const User = require("../model/user.model");
|
||||
const Group = require("../model/group.model");
|
||||
const keyService = require("../services/keys.service");
|
||||
groupService = require("../services/group.service");
|
||||
const Member = require("../model/member.model");
|
||||
|
||||
var router = express.Router();
|
||||
|
||||
router.use('*', (req, res, next) => {
|
||||
if (req.session.loggedin === true) {
|
||||
User.findOne({ where: { id: req.session.user.id } }).then((result) => {
|
||||
if (result.admin === true) {
|
||||
next()
|
||||
} else {
|
||||
res.redirect('/')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
res.redirect('/')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.get("/users", (req, res) => {
|
||||
User.findAll().then((users) => {
|
||||
res.render('admin/users', { "users": users })
|
||||
})
|
||||
})
|
||||
|
||||
router.get("/groups", (req, res) => {
|
||||
Group.findAll().then((groups) => {
|
||||
res.render('admin/groups', { "groups": groups })
|
||||
})
|
||||
})
|
||||
|
||||
router.post("/groups/add", (req, res) => {
|
||||
if (req.body.group_name) {
|
||||
groupService.addGroup(req.body.group_name).then((result) => {
|
||||
res.redirect("/admin/groups")
|
||||
})
|
||||
} else {
|
||||
res.redirect("/admin/groups")
|
||||
}
|
||||
})
|
||||
|
||||
router.get("/groups/delete/:group", (req, res) => {
|
||||
groupService.delGroup(req.params.group).then((result) => {
|
||||
res.redirect("/admin/groups")
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
router.get("/groups/:name", async (req, res) => {
|
||||
if (req.params.name === "new") {
|
||||
res.render('admin/group_new')
|
||||
} else {
|
||||
Group.findOne({ where: { name: req.params.name } }).then((group) => {
|
||||
groupService.groupUserList(req.params.name).then((result) => {
|
||||
User.findAll().then((users) => {
|
||||
for (user in users) {
|
||||
if (JSON.stringify(result).includes(users[user].dataValues.id)) {
|
||||
delete users[user]
|
||||
}
|
||||
}
|
||||
res.render('admin/group_edit', { "group": group, "inGroup": result, "outGroup": users })
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/members/:name/add/:user', (req, res) => {
|
||||
Group.findOne({ where: { name: req.params.name } }).then((result) => {
|
||||
if (result) {
|
||||
User.findOne({ where: { id: req.params.user } }).then((user) => {
|
||||
if (user) {
|
||||
Member.findOne({ where: { groupname: result.name, userId: user.id } }).then((member) => {
|
||||
if (!member) {
|
||||
Member.create({
|
||||
userId: user.id,
|
||||
groupName: result.name
|
||||
}).then((member) => {
|
||||
console.log('member added to database' + '(' + member.userId + ',' + member.groupName + ')')
|
||||
res.redirect('/admin/groups/' + result.name)
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
router.get('/members/:name/delete/:user', (req, res) => {
|
||||
Group.findOne({ where: { name: req.params.name } }).then((result) => {
|
||||
if (result) {
|
||||
User.findOne({ where: { id: req.params.user } }).then((user) => {
|
||||
if (user) {
|
||||
Member.findOne({ where: { groupname: result.name, userId: user.id } }).then((member) => {
|
||||
if (member) {
|
||||
Member.destroy({ where: { groupname: result.name, userId: user.id }}).then((member) => {
|
||||
console.log('member deleted from database' + '(' + member.userId + ',' + member.groupName + ')')
|
||||
res.redirect('/admin/groups/' + result.name)
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
const express = require('express');
|
||||
const {default: axios} = require("axios");
|
||||
const authService = require("../services/auth.service");
|
||||
|
||||
var router = express.Router();
|
||||
|
|
@ -18,6 +17,7 @@ router.get("/callback", async (req, res) => {
|
|||
req.session.access_token = access_token;
|
||||
req.session.user = user;
|
||||
req.session.loggedin = true;
|
||||
req.session.admin = user.admin;
|
||||
res.redirect("/");
|
||||
} else {
|
||||
res.send("An error occured");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
const express = require('express');
|
||||
const keyService = require("../services/keys.service");
|
||||
const Key = require("../model/key.model");
|
||||
|
||||
var router = express.Router();
|
||||
|
||||
router.get('*', (req, res, next) => {
|
||||
if (req.session.loggedin === true) {
|
||||
next()
|
||||
} else {
|
||||
res.redirect('/')
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/add", (req, res) => {
|
||||
if (req.body.key_content && req.body.key_name) {
|
||||
keyService.addKey(req.body.key_content, req.body.key_name, req.session.user.id).then((result) => {
|
||||
res.redirect("/keys")
|
||||
})
|
||||
} else {
|
||||
res.redirect("/keys")
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
router.get("/delete/:key", (req, res) => {
|
||||
keyService.delKey(req.params.key, req.session.user.id).then((result) => {
|
||||
res.redirect("/keys")
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
|
||||
router.get("/", (req, res) => {
|
||||
Key.findAll({where: {idOwner: req.session.user.id}}).then((keys) => {
|
||||
res.render('keys', { "keys": keys })
|
||||
})
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -2,7 +2,9 @@ const Sequelize = require('sequelize');
|
|||
|
||||
const sequelize = new Sequelize('accessgate', 'user', 'password', {
|
||||
dialect: 'sqlite',
|
||||
host: './database.db'
|
||||
host: './database.db',
|
||||
logging: false
|
||||
})
|
||||
|
||||
|
||||
module.exports = sequelize;
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
const Group = require('../model/group.model')
|
||||
const Members = require('../model/member.model')
|
||||
const regexp = /^\S*$/;
|
||||
const User = require('../model/user.model')
|
||||
|
||||
async function addGroup(name) {
|
||||
Group.findOne({where: { name: name}}).then((result) => {
|
||||
if (result) {
|
||||
return false;
|
||||
} else {
|
||||
if (name && regexp.test(name)) {
|
||||
Group.create({
|
||||
name: name,
|
||||
}).then((result) => {
|
||||
console.log('Group ' + result.name + ' added to database')
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function delGroup(name) {
|
||||
Group.findOne({where: { name: name}}).then((result) => {
|
||||
if (result && regexp.test(name)) {
|
||||
result.destroy()
|
||||
.then(() => {
|
||||
console.log('group ' + result.name + ' added to database')
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function groupUserList(groupName) {
|
||||
User.hasMany(Members);
|
||||
Members.belongsTo(User);
|
||||
const users = await User.findAll({ include: Members });
|
||||
var result = []
|
||||
for (x in users) {
|
||||
try {
|
||||
if (users[x].dataValues.members[0].dataValues.groupName === groupName) {
|
||||
result[x] = (users[x].dataValues)
|
||||
}
|
||||
} catch (error) {
|
||||
}}
|
||||
return result
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addGroup,
|
||||
delGroup,
|
||||
groupUserList
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
const Key = require('../model/key.model')
|
||||
|
||||
const regexp = /^\S*$/;
|
||||
|
||||
async function addKey(content, name, idOwner) {
|
||||
const id_key = idOwner.toString() + name;
|
||||
Key.findOne({where: { idKey: id_key}}).then((result) => {
|
||||
if (result) {
|
||||
return false;
|
||||
} else {
|
||||
if (content && name && idOwner && regexp.test(name, idOwner, content)) {
|
||||
Key.create({
|
||||
idKey: id_key,
|
||||
idOwner: idOwner,
|
||||
content: content,
|
||||
name: name,
|
||||
}).then((key) => {
|
||||
console.log('key ' + key.idKey + ' added to database')
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function delKey(id, idOwner) {
|
||||
Key.findOne({where: { idKey: id}}).then((result) => {
|
||||
if (result && regexp.test(id,idOwner)) {
|
||||
if (result.idOwner !== idOwner) {
|
||||
return false;
|
||||
} else {
|
||||
result.destroy()
|
||||
.then(() => {
|
||||
console.log('key ' + result.idKey + ' added to database')
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addKey,
|
||||
delKey
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
const User = require('../model/user.model')
|
||||
|
||||
async function userList(code) {
|
||||
return await User.findAll()
|
||||
}
|
||||
|
||||
function makeAdmin(userId) {
|
||||
User.findOne({ where: { id: userId } }).then((result) => {
|
||||
if (result) {
|
||||
result.admin = true;
|
||||
result.save().then(() => {
|
||||
console.log('user ' + result.login + ' is now admin')
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
userList,
|
||||
makeAdmin
|
||||
};
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<%- include('../navbar', {active: "admin-groups"}); %>
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-4"><%= group.name %></h3>
|
||||
<div class="card shadow mb-5">
|
||||
<div class="card-header py-3">
|
||||
<p class="text-primary m-0 fw-bold">Group editing</p>
|
||||
</div>
|
||||
<form method="POST" action="/keys/add/">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="col-md-6 text-nowrap">
|
||||
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable"><label class="form-label">Show <select class="d-inline-block form-select form-select-sm">
|
||||
<option value="all" selected="">all</option>
|
||||
</select> </label></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end dataTables_filter" id="dataTable_filter"><label class="form-label">
|
||||
<input type="search" class="form-control form-control-sm" id="tableInput" onkeyup="tableSearch()" aria-controls="dataTable" placeholder="Search"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive table mt-2" id="dataTable" role="grid" aria-describedby="dataTable_info">
|
||||
<table class="table my-0" id="tableEnabled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Display name</th>
|
||||
<th>github id</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% outGroup.forEach(function (member) { %>
|
||||
<tr>
|
||||
<td><img class="rounded-circle me-2" width="30" height="30" src="<%= member.avatar %>"><%= member.displayName %></td>
|
||||
<td><%= member.id %></td>
|
||||
<td style="text-align: right;"><a class="btn btn-sm btn-success" href="/admin/members/<%= group.name %>/add/<%= member.id %>"><i class="text-white fa fa-plus"></i></button></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mb-3"><button class="btn btn-primary btn-sm" type="submit">Update group</button></div>
|
||||
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="col-md-6 text-nowrap">
|
||||
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable"><label class="form-label">Show <select class="d-inline-block form-select form-select-sm">
|
||||
<option value="all" selected="">all</option>
|
||||
</select> </label></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end dataTables_filter" id="dataTable_filter"><label class="form-label">
|
||||
<input type="search" class="form-control form-control-sm" id="tableInput" onkeyup="tableSearch()" aria-controls="dataTable" placeholder="Search"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive table mt-2" id="dataTable" role="grid" aria-describedby="dataTable_info">
|
||||
<table class="table my-0" id="tableEnabled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Display name</th>
|
||||
<th>github id</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% inGroup.forEach(function (member) { %>
|
||||
<tr>
|
||||
<td><img class="rounded-circle me-2" width="30" height="30" src="<%= member.avatar %>"><%= member.displayName %></td>
|
||||
<td><%= member.id %></td>
|
||||
<td style="text-align: right;"><a class="btn btn-sm btn-danger" href="/admin/members/<%= group.name %>/delete/<%= member.id %>"><i class="far fa-trash-alt"></i></a></td>
|
||||
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('../footer'); %>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<%- include('../navbar', {active: "admin-groups"}); %>
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-4">New group: </h3>
|
||||
<div class="card shadow mb-5">
|
||||
<div class="card-header py-3">
|
||||
<p class="text-primary m-0 fw-bold">Group editing</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<form method="POST" action="/admin/groups/add/">
|
||||
<div class="mb-3"><label class="form-label"><strong>Name</strong></label><input class="form-control" type="text" name="group_name"></div>
|
||||
<div class="mb-3"><button class="btn btn-primary btn-sm" type="submit">Create group</button></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('../footer'); %>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<%- include('../navbar', {active: "admin-groups"}); %>
|
||||
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-4">Admin: Groups</h3>
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<p class="text-primary m-0 fw-bold">User list</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 text-nowrap">
|
||||
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable"><a class="btn btn-primary" href="/admin/groups/new" data-toggle="modal" >New group</a></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end dataTables_filter" id="dataTable_filter"><label class="form-label"><input type="search" class="form-control form-control-sm" aria-controls="dataTable" placeholder="Search"></label></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive table mt-2" id="dataTable" role="grid" aria-describedby="dataTable_info">
|
||||
<table class="table my-0" id="dataTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Member count</th>
|
||||
<th>Server count</th>
|
||||
<th style="text-align: right;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% groups.forEach(function (group) { %>
|
||||
<tr>
|
||||
<td><%= group.name %></td>
|
||||
<td>undefined</td>
|
||||
<td>undefined</td>
|
||||
<td style="text-align: right;"><a class="btn btn-sm btn-primary" href="/admin/groups/<%= group.name %>"><i class="far fa-edit"></i></a> <a class="btn btn-sm btn-danger" href="/admin/groups/delete/<%= group.name %>"><i class="far fa-trash-alt"></i></a></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<%- include('../footer'); %>
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<%- include('../navbar', {active: "admin-users"}); %>
|
||||
<div class="container-fluid">
|
||||
<h3 class="text-dark mb-4">Admin: Users</h3>
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<p class="text-primary m-0 fw-bold">User list</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 text-nowrap">
|
||||
<div id="dataTable_length" class="dataTables_length" aria-controls="dataTable"><label class="form-label">Show <select class="d-inline-block form-select form-select-sm">
|
||||
<option value="all" selected="">all</option>
|
||||
</select> </label></div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end dataTables_filter" id="dataTable_filter"><label class="form-label">
|
||||
<input type="search" class="form-control form-control-sm" id="tableInput" onkeyup="tableSearch()" aria-controls="dataTable" placeholder="Search"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive table mt-2" id="dataTable" role="grid" aria-describedby="dataTable_info">
|
||||
<table class="table my-0" id="tableEnabled">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Display name</th>
|
||||
<th>github id</th>
|
||||
<th>Admin</th>
|
||||
<th>Groups</th>
|
||||
<th>Last login</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% users.forEach(function (user) { %>
|
||||
<tr>
|
||||
<td><img class="rounded-circle me-2" width="30" height="30" src="<%= user.avatar %>"><%= user.displayName %></td>
|
||||
<td><%= user.id %></td>
|
||||
<td><%= user.admin %></td>
|
||||
<td>
|
||||
<span class="badge bg-primary">admin</span>
|
||||
</td>
|
||||
<td><%= user.updatedAt %></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr></tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%- include('../footer'); %>
|
||||
|
|
@ -5,7 +5,28 @@
|
|||
</footer>
|
||||
</div><a class="border rounded d-inline scroll-to-top" href="#page-top"><i class="fas fa-angle-up"></i></a>
|
||||
</div>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="/static/assets/js/script.min.js"></script>
|
||||
<script>
|
||||
function tableSearch() {
|
||||
var input, filter, table, tr, td, i, txtValue;
|
||||
input = document.getElementById("tableInput");
|
||||
filter = input.value.toUpperCase();
|
||||
table = document.getElementById("tableEnabled");
|
||||
tr = table.getElementsByTagName("tr");
|
||||
for (i = 0; i < tr.length; i++) {
|
||||
td = tr[i].getElementsByTagName("td")[0];
|
||||
if (td) {
|
||||
txtValue = td.textContent || td.innerText;
|
||||
if (txtValue.toUpperCase().indexOf(filter) > -1) {
|
||||
tr[i].style.display = "";
|
||||
} else {
|
||||
tr[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -48,25 +48,28 @@
|
|||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Key</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% keys.forEach(function (key) { %>
|
||||
<tr>
|
||||
<td>MacBook Pro</td>
|
||||
<td>Lorem ipsum</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PC</td>
|
||||
<td>Lorem ipsum</td>
|
||||
<td><%= key.name %></td>
|
||||
|
||||
<td><%= key.content %></td>
|
||||
|
||||
<td style="text-align: right;"><a class="btn btn-sm btn-danger" href="/keys/delete/<%= key.idKey %>"><i class="far fa-trash-alt"></i></button></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<form>
|
||||
<div class="mb-3"><label class="form-label" for="signature"><strong>Name</strong></label><input class="form-control" type="text"></div>
|
||||
<div class="mb-3"><label class="form-label" for="signature"><strong>Key</strong></label><textarea class="form-control" id="signature-1" rows="4" name="signature"></textarea></div>
|
||||
<form method="POST" action="/keys/add/">
|
||||
<div class="mb-3"><label class="form-label"><strong>Name</strong></label><input class="form-control" type="text" name="key_name"></div>
|
||||
<div class="mb-3"><label class="form-label"><strong>Key</strong></label><textarea class="form-control" name="key_content" rows="2"></textarea></div>
|
||||
<div class="mb-3"></div>
|
||||
<div class="mb-3"><button class="btn btn-primary btn-sm" type="submit">Add key</button></div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -4,17 +4,19 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
|
||||
<title>Dashboard - AccessGate</title>
|
||||
<title>AccessGate</title>
|
||||
<link rel="stylesheet" href="/static/assets/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i&display=swap">
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/styles.min.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
|
||||
<script src="https://cdn.rawgit.com/harvesthq/chosen/gh-pages/chosen.jquery.min.js"></script>
|
||||
<link href="https://cdn.rawgit.com/harvesthq/chosen/gh-pages/chosen.min.css" rel="stylesheet"/>
|
||||
</head>
|
||||
|
||||
<body id="page-top">
|
||||
<div id="wrapper">
|
||||
<nav class="navbar align-items-start sidebar sidebar-dark accordion bg-gradient-primary p-0 navbar-dark">
|
||||
<div class="container-fluid d-flex flex-column p-0"><a class="navbar-brand d-flex justify-content-center align-items-center sidebar-brand m-0" href="#">
|
||||
<div class="container-fluid d-flex flex-column p-0"><a class="navbar-brand d-flex justify-content-center align-items-center sidebar-brand m-0" href="/">
|
||||
<div class="sidebar-brand-icon rotate-n-15"><i class="fas fa-lock"></i></div>
|
||||
<div class="sidebar-brand-text mx-3"><span>AccessGate</span></div>
|
||||
</a>
|
||||
|
|
@ -22,9 +24,13 @@
|
|||
<ul class="navbar-nav text-light" id="accordionSidebar">
|
||||
<li class="nav-item"><a class="nav-link <%if(active=="index"){%>active<%}%>" href="/"><i class="fas fa-tachometer-alt"></i><span>Dashboard</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link <%if(active=="keys"){%>active<%}%>" href="/keys"><i class="fas fa-key"></i><span>Keys</span></a></li>
|
||||
<% if (session_user.admin) { %>
|
||||
|
||||
<li class="nav-item"><a class="nav-link <%if(active=="admin-users"){%>active<%}%>" href="/admin/users"><i class="far fa-user"></i><span>Users</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link <%if(active=="admin-groups"){%>active<%}%>" href="/admin/groups"><i class="fas fa-stream"></i><span>Groups</span></a></li>
|
||||
<li class="nav-item"><a class="nav-link <%if(active=="admin-servers"){%>active<%}%>" href="/admin/servers"><i class="far fa-hdd"></i><span>Servers</span></a></li>
|
||||
<% } %>
|
||||
|
||||
<li class="nav-item"><a class="nav-link" href="/auth/logout"><i class="far fa-user-circle"></i><span>Disconnect</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -38,10 +44,7 @@
|
|||
</form>
|
||||
<ul class="navbar-nav flex-nowrap ms-auto">
|
||||
<li class="nav-item dropdown no-arrow">
|
||||
<div class="nav-item dropdown no-arrow"><a class="dropdown-toggle nav-link" aria-expanded="false" data-bs-toggle="dropdown" href="#"><span class="d-none d-lg-inline me-2 text-gray-600 small">Valentin - itsmrval</span><img class="border rounded-circle img-profile" src="assets/img/avatars/43043885.jpeg"></a>
|
||||
<div class="dropdown-menu shadow dropdown-menu-end animated--grow-in"><a class="dropdown-item" href="#"><i class="fas fa-user fa-sm fa-fw me-2 text-gray-400"></i> Profile</a><a class="dropdown-item" href="#"><i class="fas fa-cogs fa-sm fa-fw me-2 text-gray-400"></i> Settings</a><a class="dropdown-item" href="#"><i class="fas fa-list fa-sm fa-fw me-2 text-gray-400"></i> Activity log</a>
|
||||
<div class="dropdown-divider"></div><a class="dropdown-item" href="#"><i class="fas fa-sign-out-alt fa-sm fa-fw me-2 text-gray-400"></i> Logout</a>
|
||||
</div>
|
||||
<div class="nav-item dropdown no-arrow"><a class="dropdown-toggle nav-link"><span class="d-none d-lg-inline me-2 text-gray-600 small"><%= session_user.login %></span><img class="border rounded-circle img-profile" src="<%= session_user.avatar %>"></a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
Loading…
Reference in New Issue