Version 0.6.0 - Ajout des utilisateurs et des paramètres V1
All checks were successful
Neutral/pipeline/head This commit looks good

This commit is contained in:
Raphael 2024-01-07 23:27:49 +01:00
parent ff42630c8d
commit 43d65d093b
20 changed files with 2632 additions and 1130 deletions

View File

@ -14,7 +14,7 @@ const users = require("./users")
module.exports.check = function(token) {
var isApproved = false;
var username = null
users.getUsers().forEach((fetchUser) => {
users.fetchUsers().forEach((fetchUser) => {
if(fetchUser.tokens.includes(token)) {
isApproved = true
username = fetchUser.username
@ -42,8 +42,8 @@ module.exports.login = function(data) {
var username = data.username
var password = data.password
if(users.getUsers().has(username)) {
const user = users.getUsers().get(username)
if(users.fetchUsers().has(username)) {
const user = users.fetchUsers().get(username)
if(password == user.getPassword()) {
const token = user.generateToken()
alog.log("Connexion approuvé de l'utilisateur : " + username)
@ -67,7 +67,7 @@ module.exports.login = function(data) {
module.exports.signout = function(token) {
var isDone = false;
var username = null
users.getUsers().forEach((fetchUser) => {
users.fetchUsers().forEach((fetchUser) => {
if(fetchUser.tokens.includes(token)) {
isDone = true
username = fetchUser.username
@ -92,7 +92,7 @@ module.exports.signout = function(token) {
module.exports.getUserByToken = function(token) {
var isApproved = false;
var userGetted = null
users.getUsers().forEach((fetchUser) => {
users.fetchUsers().forEach((fetchUser) => {
if(fetchUser.tokens.includes(token)) {
userGetted = fetchUser
}

View File

@ -35,3 +35,14 @@ module.exports.updateFile = function (file) {
}
}
module.exports.getSettings = function () {
const file = this.getFile()
return {"jenkins_token": file.JENKINS_TOKEN, "omega_token": file.OMEGA_KEY}
}
module.exports.saveSettings = function (settings) {
const file = this.getFile()
file.JENKINS_TOKEN = settings.jenkins_token
file.OMEGA_KEY = settings.omega_token
this.updateFile(file)
}

View File

@ -33,6 +33,12 @@ module.exports.getFiles = function(root) {
}
if(root == "logpath") {
root = __glob.LOGS
}
if(!fs.existsSync(root)) {
response.content = "NOT_EXIST"

View File

@ -10,6 +10,7 @@ const __glob = {
USERS: root + path.sep + "data" + path.sep + "users.json",
CONFIG: root + path.sep + "data" + path.sep + "config.json",
SHARED: root + path.sep + "data" + path.sep + "shared",
USERS_IMAGES: root + path.sep + "public" + path.sep + 'images' + path.sep + "users",
};

View File

@ -3,7 +3,9 @@ const fs = require("fs")
const path = require("path")
const { __glob } = require("./global-variables.js")
const auth = require("./auth.js")
const users = require("./users.js")
const files = require("./files.js")
const config = require("./config.js")
const links = require("./links.js")
const service = require("./services.js")
const pipeline = require("./pipelines.js")
@ -11,6 +13,7 @@ const plog = new LogType("Web")
const cook = require("cookie")
const http = require("http")
const servermetrics = require("./server-metrics.js")
const pm2 = require('pm2');
/**
* NOTE INTERNE
@ -25,11 +28,16 @@ const servermetrics = require("./server-metrics.js")
module.exports.serverIO = function(server) {
const io = require('socket.io')(server)
const io = require('socket.io')(server, {
maxHttpBufferSize: 1e8,
pingTimeout: 60000
})
io.on("connection", (socket) => {
let token = cook.parse(socket.handshake.headers.cookie).token
const user = auth.getUserByToken(token)
var user = auth.getUserByToken(token)
if(user) {
plog.log("Connexion au panel par '" + user.username + "' avec le socket : " + socket.id)
@ -40,7 +48,7 @@ module.exports.serverIO = function(server) {
// Get Users
GetRequest("USERINFO", () => {
user = auth.getUserByToken(token)
GetAnswer("USERINFO", {username: user.username, display_name: user.display_name ,picture: user.picture, permission: user.permission})
})
@ -163,11 +171,57 @@ module.exports.serverIO = function(server) {
}
socket.on("disconnect", () => {
if(user.checkPermission("USERS")) {
GetRequest("US_ALL", async () => {
GetAnswer("US_ALL", await users.getAllUsers())
})
PostRequest("US_ADD", async (settings) => {
PostAnswer("US_ADD", await users.addUser(settings))
})
PostRequest("US_DELETE", async (settings) => {
PostAnswer("US_DELETE", await users.deleteUser(settings))
})
PostRequest("US_EDIT", async (settings) => {
PostAnswer("US_EDIT", await users.editUser(settings))
})
}
if(user.checkPermission("SETTINGS")) {
PostRequest("SETTINGS_SAVE", async (settings) => {
PostAnswer("SETTINGS_SAVE", await config.saveSettings(settings))
})
PostRequest("SERVER_RESTART", async () => {
pm2.restart('Neutral')
})
PostRequest("SERVER_STOP", async () => {
pm2.stop('Neutral')
})
GetRequest("SERVER_GET_LOGS", async () => {
GetAnswer("SERVER_GET_LOGS", await fs.readdirSync(__glob.LOGS))
})
PostRequest("SERVER_READ_LOG", async (logs) => {
PostAnswer("SERVER_READ_LOG", await fs.readFileSync(__glob.LOGS + path.sep + logs).toString())
})
GetRequest("SETTINGS_GET", async () => {
GetAnswer("SETTINGS_GET", await config.getSettings())
})
}
socket.on("disconnect", (reason) => {
plog.log("Déconnexion du panel par '" + user.username + "' avec le socket : " + socket.id)
})
socket.on("connect_error", (err) => {
console.log(err)
console.log(err.message); // prints the message associated with the error
});
function GetRequest(GQname, GQcallback) {
socket.on("GET/" + GQname, () => {

View File

@ -18,22 +18,30 @@ function setup() {
}
}
/**
*
* @returns Liste des utilisateurs
*/
module.exports.getUsers = function () {
module.exports.getAllUsers = async function() {
return new Promise(async (resolve, reject) => {
const users = await this.fetchUsers()
return usersList
// Remove for every people the password & the tokens
for(var user of users) {
user = user[1]
user.password = null
user.tokens = null
}
resolve(JSON.stringify(Array.from(users)))
})
}
/**
* Get all users from Users Data Base
*/
module.exports.fetchUsers = function () {
ulog.step.init("fetch_user", "Récupération de tous les utilisateurs inscrit dans la base de donnée")
const userFile = getFile()
usersList = new Map()
@ -80,6 +88,8 @@ module.exports.fetchUsers = function () {
ulog.step.end("fetch_user")
return usersList
}
/**
@ -177,6 +187,7 @@ module.exports.User = class {
}
userFile.push(this)
updateFile(userFile)
usersList.set(this.username, this)
}
@ -298,12 +309,37 @@ module.exports.User = class {
}
setNewUsername(text) {
this.#sync()
module.exports.deleteUser(this.username)
this.username = text
this.register()
ulog.log("Le nom d'utilisateur de l'utilisateur a été modifié : " + this.username)
}
setLastLogin(text) {
this.#sync()
this.lastLogin = text
this.register()
}
setPicture(file) {
this.#sync()
var pictureDir = __glob.USERS_IMAGES + path.sep + uuid.v4().toString() + ".png"
fs.writeFileSync(pictureDir, file)
this.picture = pictureDir.replace(__glob.USERS_IMAGES + path.sep, "/images/users/")
this.register()
}
setPermissions(permissions) {
this.#sync()
this.permission = permissions
this.register()
}
#sync() {
for(var userGet of usersList.keys()) {
@ -321,6 +357,108 @@ module.exports.User = class {
}
}
module.exports.addUser = function(settings) {
if(settings.username == '') {
ulog.error("Le nom d'utilisateur est manquant")
return "USERNAME_MISSING"
} else if(settings.password == '') {
ulog.error("Le mot de passe est manquant")
return "PASSWORD_MISSING"
} else if(settings.display_name == '') {
ulog.error("Le nom d'affichage est manquant")
return "DISPLAY_NAME_MISSING"
} else if(this.getUser(settings.username)) {
ulog.error("L'utilisateur existe déjà : " + settings.username)
return "ALREADY_EXIST"
} else {
ulog.step.init("add_user", "Ajout d'un utilisateur dans la base de donnée : " + settings.username)
var pictureDir = null
if(settings.picture == null) {
pictureDir = "/images/users/default.jpg"
} else {
pictureDir = __glob.USERS_IMAGES + path.sep + uuid.v4().toString() + ".png"
fs.writeFileSync(pictureDir, settings.picture)
}
const user = new this.User({
username: settings.username,
display_name: settings.display_name,
permission: settings.permissions,
picture: pictureDir.replace(__glob.USERS_IMAGES + path.sep, "/images/users/")
})
user.setPassword(settings.password)
user.register()
ulog.step.end("add_user")
}
}
module.exports.deleteUser = function(username) {
ulog.step.init("delete_user", "Suppression d'un utilisateur dans la base de donnée : " + username)
const user = this.getUser(username)
user.unregister()
ulog.step.end("delete_user")
return "OK"
}
module.exports.getUser = function(username) {
return usersList.get(username)
}
module.exports.editUser = function(settings) {
if(settings.username == '') {
ulog.error("Le nom d'utilisateur est manquant")
return "USERNAME_MISSING"
} else if(settings.display_name == '') {
ulog.error("Le nom d'affichage est manquant")
return "DISPLAY_NAME_MISSING"
} else {
ulog.step.init("edit_user", "Modification d'un utilisateur dans la base de donnée : " + settings.username)
const user = this.fetchUsers().get(settings.username)
if(user) {
console.log(settings)
if(settings.newusername && settings.newusername != settings.username) {
if(this.getUser(settings.newusername)) {
ulog.error("L'utilisateur existe déjà : " + settings.username)
return "ALREADY_EXIST"
} else {
user.setNewUsername(settings.newusername)
}
}
if(settings.display_name) {
user.setDisplayName(settings.display_name)
}
if(settings.password) {
user.setPassword(settings.password)
}
if(settings.picture) {
user.setPicture(settings.picture)
}
if(settings.permissions) {
user.setPermissions(settings.permissions)
}
ulog.step.end("edit_user")
return "OK"
} else {
ulog.step.end("edit_user")
return "NOT_EXIST"
}
}
}
/**
*

2691
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "neutral",
"version": "0.5.0",
"version": "0.6.0",
"description": "Panel d'administration de Raphix",
"main": "index.js",
"scripts": {
@ -26,9 +26,11 @@
"ejs": "~2.6.1",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"install": "^0.13.0",
"loguix": "1.4.1",
"nodemon": "^3.0.1",
"os-utils": "^0.0.14",
"pm2": "^5.3.0",
"serve-favicon": "^2.0.4",
"socket.io": "^4.7.2",
"uuid": "^9.0.1"

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -74,8 +74,6 @@ class TextResponse {
this.element = getID(this.name)
this.element.innerHTML = " "
this.element.style.fontSize = "14px"
this.element.style.position = "sticky"
this.element.style.width = this.element.parentElement.offsetWidth + "px"
this.element.style.textAlign = "center"
}
@ -103,6 +101,11 @@ class TextResponse {
this.element.style.fontSize = size
}
setWidth(width) {
this.element.style.width = width
}
}
@ -110,6 +113,7 @@ const AllViews = new Map()
var zIndex = 5
/**
* Permet de créer une fenêtre
* @param {object} properties Propriétés de la fenêtre
@ -123,7 +127,7 @@ class ViewWindow {
ViewPopupHTML = null
ViewPopupTitle = null
ViewItem = new ViewItem(this)
constructor(properties) {
constructor (properties) {
if(!AllViews.has(properties.title)) {
this.ViewProperties = properties
@ -656,7 +660,7 @@ class Service {
const stopButton = getID(`${this.name}_stop`)
const restartButton = getID(`${this.name}_restart`)
const info = new TextResponse("sv-power-info")
info.setWidth("350px")
if(this.isOnline) {
@ -950,6 +954,221 @@ class Pipeline {
}
class User {
constructor(properties) {
this.username = properties.username
this.display_name = properties.display_name
this.picture = properties.picture
this.permission = properties.permission
this.View = properties.window
this.Component = properties.component
}
generateHTML() {
return `
<div class='user-line'>
<div class='user-line-info'>
<img class='taskbar-image' src='${this.picture}' alt='${this.username}'>
<div>
<p class='user-line-displayname'>${this.display_name}</p>
<p class='taskbar-username'>${this.username}</p>
</div>
</div>
<div class='user-actions'>
<button id='${this.username}_edit' class='btn blue'><span><i class='fa fa-pencil'></i> Editer<span></button>
${this.username == "raphix" ? "" : `<button id='${this.username}_delete' class='btn red'><span><i class='fa fa-trash'></i> Supprimer<span></button>`}
</div>
</div>
`
}
loadScript() {
const editButton = getID(`${this.username}_edit`)
const deleteButton = getID(`${this.username}_delete`)
editButton.addEventListener("click", () => {
this.View.createPopup({
title: `<i class='fa fa-pencil'></i> Editer l'utilisateur : ${this.username}`,
content: `
<div class='us-edit'>
<div class='user-edit-actual'>
<img class='taskbar-image' src='${this.picture}' alt='${this.username}'>
<p class='user-line-displayname'>${this.display_name}</p>
<p class='taskbar-username'>${this.username}</p>
</div>
<div class='user-edit-line'>
<p class='user-edit-info'>Nom d'utilisateur</p>
<input id='${this.username}_editusername' class='field' type='text' value='${this.username}'>
</div>
<div class='user-edit-line'>
<p class='user-edit-info'>Nom d'affichage</p>
<input id='${this.username}_editdisplay' class='field' type='text' value='${this.display_name}'>
</div>
<div class='user-edit-line'>
<p class='user-edit-info'>Mot de passe</p>
<input id='${this.username}_editpassword' class='field' type='password' id='user-edit-password'>
</div>
<div class='user-edit-line'>
<p class='user-edit-info'>Permissions</p>
<div class='permissions'>
<div>
<input type="checkbox" id="${this.username}_perm_FILES_EXPLORER">
<label for="${this.username}_perm_FILES_EXPLORER">Fichiers</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_SERVICES">
<label for="${this.username}_perm_SERVICES">Services</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_LINKS">
<label for="${this.username}_perm_LINKS">Liens</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_SERVERS">
<label for="${this.username}_perm_SERVERS">Serveurs</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_PIPELINES">
<label for="${this.username}_perm_PIPELINES">Pipelines</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_METRICS">
<label for="${this.username}_perm_METRICS">Metrics</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_USERS">
<label for="${this.username}_perm_USERS">Utilisateurs</label>
</div>
<div>
<input type="checkbox" id="${this.username}_perm_SETTINGS">
<label for="${this.username}_perm_SETTINGS">Paramètres</label>
</div>
</div>
<br>
<div class='user-edit-line'>
<p class='user-edit-info'>Photo de profil</p>
<input type="file" id="${this.username}_addpicture" accept="image/png, image/jpeg">
</div>
<br>
<span id="${this.username}_returninfo"></span>
</div>
<div class="user-edit-actions">
<button id="${this.username}_cedit" class="btn green"><span><i class='fa fa-pencil'></i> Editer</span></button>
<button id="${this.username}_edittokens" class="btn yellow"><span><i class='fa fa-trash'></i> Tokens</span></button>
</div>
</div>
`
})
const editCButton = getID(`${this.username}_cedit`)
const editTokensButton = getID(`${this.username}_edittokens`)
const editUsername = getID(`${this.username}_editusername`)
const editDisplay = getID(`${this.username}_editdisplay`)
const editPassword = getID(`${this.username}_editpassword`)
const editPicture = getID(`${this.username}_addpicture`)
const returnInfo = new TextResponse(`${this.username}_returninfo`)
const editPermissions = new Array()
editPermissions.push(getID(`${this.username}_perm_FILES_EXPLORER`))
editPermissions.push(getID(`${this.username}_perm_SERVICES`))
editPermissions.push(getID(`${this.username}_perm_LINKS`))
editPermissions.push(getID(`${this.username}_perm_SERVERS`))
editPermissions.push(getID(`${this.username}_perm_PIPELINES`))
editPermissions.push(getID(`${this.username}_perm_METRICS`))
editPermissions.push(getID(`${this.username}_perm_USERS`))
editPermissions.push(getID(`${this.username}_perm_SETTINGS`))
for(const actualPerm of this.permission) {
getID(`${this.username}_perm_${actualPerm}`).checked = true
}
editUsername.addEventListener("change", () => {
editUsername.value = editUsername.value.replace(/[^a-zA-Z0-9]/g, '')
})
editCButton.addEventListener("click", () => {
const newPerms = new Array()
for(const permission of editPermissions) {
if(permission.checked) {
newPerms.push(permission.id.replace(`${this.username}_perm_`, ""))
}
}
const request = post(`US_EDIT`, {username: this.username, newusername: editUsername.value, display_name: editDisplay.value, password: editPassword.value, permissions: newPerms, picture: editPicture.files[0]})
request.then((answer) => {
if(answer == "ALREADY_EXIST") {
returnInfo.err("L'utilisateur existe déjà !")
} else if(answer == "USERNAME_MISSING") {
returnInfo.err("Le nom d'utilisateur est manquant !")
} else if(answer == "DISPLAY_NAME_MISSING") {
returnInfo.err("Le nom d'affichage est manquant !")
} else if(answer == "PASSWORD_MISSING") {
returnInfo.err("Le mot de passe est manquant !")
} else {
this.View.destroyPopup()
this.View.destroy()
this.Component.forceWindow()
loadUserInfo()
}
})
})
})
if(this.username != "raphix") {
deleteButton.addEventListener("click", () => {
this.View.createPopup({
title: `<i class='fa fa-trash'></i> Supprimer l'utilisateur : ${this.username}`,
content: `
<p class='us-delete'>Voulez-vous vraiment supprimer l'utilisateur <strong>${this.username}</strong> ?</p>
<button id="${this.username}_deleteconfirm" class="btn red"><span><i class='fa fa-trash'></i> Supprimer</span></button>
`
})
const deleteCButton = getID(`${this.username}_deleteconfirm`)
deleteCButton.addEventListener("click", () => {
const request = post(`US_DELETE`, this.username)
request.then((answer) => {
if(answer == "OK") {
this.View.destroyPopup()
this.View.destroy()
this.Component.forceWindow()
} else {
console.log(answer)
}
})
})
})
}
}
}
/**
* Permet de créer un item de la barre des tâches

View File

@ -12,10 +12,6 @@ explorer.createWindow(() => {
width: "1000px",
height: "600px"
})
console.log("")
@ -38,6 +34,15 @@ explorer.createWindow(() => {
loadFiles(result)
})
}
function goLogPath() {
const rFiles = post("FX_GET", "logpath")
rFiles.then((result) => {
loadFiles(result)
})
}
View.setContent(`
@ -45,6 +50,7 @@ explorer.createWindow(() => {
<div class='fx-bar'>
<span id='${View.getViewTitle()}_home' class='btn-cover'><i class='fa fa-home'></i></span>
<span id='${View.getViewTitle()}_sharebtn' class='btn-cover'><i class="fa-solid fa-share-from-square"></i></span>
<span id='${View.getViewTitle()}_logsdir' class='btn-cover'><i class="fa-solid fa-file-lines"></i></i></span>
<input class='fx-root-input' type="text" id='${View.getViewTitle()}_rootInput'>
<div class='fx-bar-actions'>
<button id='${View.getViewTitle()}_newFolder' class='btn blue'><span><i class='fa fa-folder'></i> Nouv. dossier</span></button>
@ -63,6 +69,9 @@ explorer.createWindow(() => {
const newFile = getID(View.getViewTitle() + '_newFile')
const home = getID(View.getViewTitle() + '_home')
const sharebtn = getID(View.getViewTitle() + '_sharebtn')
const logsdir = getID(View.getViewTitle() + '_logsdir')
@ -127,6 +136,12 @@ explorer.createWindow(() => {
})
logsdir.addEventListener("click", () => {
goLogPath()
})
newFolder.addEventListener("click", () => {
View.createPopup({
@ -263,6 +278,7 @@ explorer.createWindow(() => {
}
const file = fileuploadInput.files[0]
console.log(file)
const reqFiles = post("FX_UPLOAD", {name: file.name ,root: rootInput.value, file: file})

View File

@ -1,55 +1,66 @@
const infoUsername = getID("infoUsername")
const infoUserimage = getID("infoUserimage")
const infoDisplayname = getID("infoDisplayname")
const views = getID("views")
const panelBox = getID("panel-box")
// User Request
const REQ_user = get("USERINFO")
loadUserInfo()
REQ_user.then((ANS_user) => {
infoUserimage.src = ANS_user.picture
infoUsername.innerHTML = ANS_user.username
infoDisplayname.innerHTML = ANS_user.display_name
const permissions = ANS_user.permission
function loadUserInfo() {
const infoUsername = getID("infoUsername")
const infoUserimage = getID("infoUserimage")
const infoDisplayname = getID("infoDisplayname")
const views = getID("views")
const panelBox = getID("panel-box")
const AvailableViews = new Array()
permissions.forEach((permValue) => {
AllComponents.forEach((component) => {
if(component.permission == permValue) {
component.inject(AvailableViews)
}
})
const REQ_user = get("USERINFO")
REQ_user.then((ANS_user) => {
console.log(ANS_user)
infoUserimage.src = ANS_user.picture
infoUsername.innerHTML = ANS_user.username
infoDisplayname.innerHTML = ANS_user.display_name
const permissions = ANS_user.permission
const AvailableViews = new Array()
permissions.forEach((permValue) => {
AllComponents.forEach((component) => {
if(component.permission == permValue) {
component.inject(AvailableViews)
}
})
})
if(AvailableViews.join("") == "") {
AvailableViews.push("<p style='width: 100%;' class='yellow t-center'><i class='fa-solid fa-warning'></i> Aucune permission ne semble vous êtes accordée<br>Demandez à Raphix afin de résoudre ce problème</p>")
views.classList.remove("views-box")
panelBox.style.justifyContent = "unset"
console.log(panelBox.style)
} else {
views.classList.add("views-box")
}
views.innerHTML = AvailableViews.join("")
// BindView
AllComponents.forEach((component) => {
component.bindView()
})
})
if(AvailableViews.join("") == "") {
AvailableViews.push("<p style='width: 100%;' class='yellow t-center'><i class='fa-solid fa-warning'></i> Aucune permission ne semble vous êtes accordée<br>Demandez à Raphix afin de résoudre ce problème</p>")
views.classList.remove("views-box")
panelBox.style.justifyContent = "unset"
console.log(panelBox.style)
} else {
views.classList.add("views-box")
}
views.innerHTML = AvailableViews.join("")
// BindView
AllComponents.forEach((component) => {
component.bindView()
})
})
}

View File

@ -12,8 +12,7 @@ socket.on("connect", () => {
console.log("Connecté au serveur par le Socket avec l'ID : " + socket.id)
});
socket.on("disconnect", () => {
socket.on("disconnect", (log) => {
window.location.href = "/"
})

View File

@ -51,7 +51,8 @@ function login() {
response = await response.text()
if(response == "AUTH_FAILED") {
loginInfo.err("Le nom d'utilisateur et le mot de passe sont incorrects.")
} else if(response == "AUTH_SUCCESS") {

View File

View File

@ -0,0 +1,123 @@
settings.createWindow(async () => {
const View = new ViewWindow({
title: `<i class="fa fa-cog"></i> Paramètres`,
width: "500px",
height: "620px"
})
View.setContent(`
<div style='overflow-y: auto; height: 550px;'>
<div class="category">
<p>Options d'alimentation</p>
<div class='st-act'>
<button id="st-restart" class="btn yellow"><span>Redémarrer</span></button>
<button id="st-stop" class="btn red"><span> Arrêter</span></button>
</div>
</div>
<div class="category">
<p>Configuration des Tokens</p>
<p class='user-line-displayname'>Jenkins</p>
<input class='field' type="text" id="jenkins_token" placeholder="Token Jenkins">
<p class='user-line-displayname'> Omega </p>
<input class='field' type="text" id="omega_token" placeholder="Token Omega">
<button id="st-save" class="btn green"><span> Sauvegarder</span></button>
</div>
<div class="category">
<p>Accès aux logs</p>
<select id="all-logs" class="field">
<option>Chargment en cours ...</option>
</select>
<button id="read-logs" class="btn green"><span>Lire</span></button>
</div>
</div>
`)
const allLogs = document.getElementById("all-logs")
const readLogs = document.getElementById("read-logs")
get("SERVER_GET_LOGS").then((logs) => {
logs.reverse()
allLogs.innerHTML = logs.map((log) => {
return `<option value="${log}">${log}</option>`
}).join("")
})
readLogs.addEventListener("click", () => {
const log = allLogs.value
post("SERVER_READ_LOG", log).then((logContent) => {
const logView = new ViewWindow({
title: `<i class="fa fa-file"></i> ${log}`,
width: "1000px",
height: "520px"
})
logContent = logContent.replaceAll("[INFO]", "<span class='blue'>[INFO]</span>")
logContent = logContent.replaceAll("[WARN]", "<span class='yellow'>[WARN]</span>")
logContent = logContent.replaceAll("[ERROR]", "<span class='lightred'>[ERROR]</span>")
logContent = logContent.replaceAll("[STEP]", "<span class='green'>[STEP]</span>")
logContent = logContent.replaceAll("[Users]", "<span style='color:#c7b8ff; '>[Users]</span>")
logContent = logContent.replaceAll("[Web]", "<span style='color:#fffd8a; '>[Web]</span>")
logContent = logContent.replaceAll("[Serveur]", "<span style='color:#ff7a5c; '>[Serveur]</span>")
logContent = logContent.replaceAll("[Authentification]", "<span style='color:#d9e6ff; '>[Authentification]</span>")
// Get every line of logs and add a set the style in blue when it's the date in []
const logLines = logContent.split("\n")
const newLogLines = new Array()
logLines.forEach((line) => {
if(line.startsWith("[") && line.includes("]")) {
const date = line.split("]")[0] + "]"
const content = line.replace(date, "")
newLogLines.push(`<span style='color: #a6c2f7;'>${date}</span>${content}\n`)
} else {
newLogLines.push(`${line}\n`)
}
})
logView.setContent(`
<div style='overflow-y: auto; height: 450px;'>
<pre style='font-size: 12px'>${newLogLines.join("")}</pre>
</div>
`)
})
})
const restartButton = document.getElementById("st-restart")
const stopButton = document.getElementById("st-stop")
const saveButton = document.getElementById("st-save")
const jenkinsToken = document.getElementById("jenkins_token")
const omegaToken = document.getElementById("omega_token")
get("SETTINGS_GET").then((settings) => {
jenkinsToken.value = settings.jenkins_token
omegaToken.value = settings.omega_token
})
restartButton.addEventListener("click", () => {
post("SERVER_RESTART")
})
stopButton.addEventListener("click", () => {
post("SERVER_STOP")
})
saveButton.addEventListener("click", () => {
post("SETTINGS_SAVE", {
jenkins_token: jenkinsToken.value,
omega_token: omegaToken.value
})
get("SETTINGS_GET").then((settings) => {
jenkinsToken.value = settings.jenkins_token
omegaToken.value = settings.omega_token
})
})
})

180
public/javascripts/user.js Normal file
View File

@ -0,0 +1,180 @@
users.createWindow(async () => {
const usersComponent = users
const View = new ViewWindow({
title: `<i class="fa fa-users"></i> Gestion des utilisateurs`,
width: "500px",
height: "700px"
})
loadUsers()
function loadUsers() {
View.setContent(`
<div class="users">
<div class='us-bar'>
<p> <strong>Utilisateurs</strong> : <span id='${View.getViewTitle()}_number'><i>Calcul en cours</i></span></p>
<button id='${View.getViewTitle()}_add' class='btn blue'><span><i class='fa fa-add'></i> Ajouter un utilisateur</span></button>
</div>
<div class='us-users' id='${View.getViewTitle()}_users'>
</div>
</div>`)
const usersList = new Array()
const users = get("US_ALL")
const usersDiv = document.getElementById(`${View.getViewTitle()}_users`)
const usersNumber = document.getElementById(`${View.getViewTitle()}_number`)
const addButton = document.getElementById(`${View.getViewTitle()}_add`)
addButton.addEventListener("click", () => {
View.createPopup({
title: "Ajouter un utilisateur",
content: `
<div class='us-add'>
<p>Nom d'utilisateur</p>
<input class='field' type="text" id="us-add-username" placeholder="Nom d'utilisateur">
<p>Nom d'affichage</p>
<input class='field' type="text" id="us-add-displayname" placeholder="Nom d'affichage">
<p>Mot de passe</p>
<input class='field' type="password" id="us-add-password" placeholder="Mot de passe">
<p>Permissions</p>
<div class='permissions'>
<div>
<input type="checkbox" id="perm_FILES_EXPLORER">
<label for="perm_FILES_EXPLORER">Fichiers</label>
</div>
<div>
<input type="checkbox" id="perm_SERVICES">
<label for="perm_SERVICES">Services</label>
</div>
<div>
<input type="checkbox" id="perm_LINKS">
<label for="perm_LINKS">Liens</label>
</div>
<div>
<input type="checkbox" id="perm_SERVERS">
<label for="perm_SERVERS">Serveurs</label>
</div>
<div>
<input type="checkbox" id="perm_PIPELINES">
<label for="perm_PIPELINES">Pipelines</label>
</div>
<div>
<input type="checkbox" id="perm_METRICS">
<label for="perm_METRICS">Metrics</label>
</div>
<div>
<input type="checkbox" id="perm_USERS">
<label for="perm_USERS">Utilisateurs</label>
</div>
<div>
<input type="checkbox" id="perm_SETTINGS">
<label for="perm_SETTINGS">Paramètres</label>
</div>
</div>
<p>Photo de profil</p>
<input type="file" id="us-add-picture" accept="image/png, image/jpeg">
<span id='user-addreturn-info'></span>
<button id='us-add-button' class='btn green'><span>Ajouter</span></button>
</div>
`
})
const addButton = document.getElementById("us-add-button")
const username = document.getElementById("us-add-username")
const displayname = document.getElementById("us-add-displayname")
const password = document.getElementById("us-add-password")
const picture = document.getElementById("us-add-picture")
const permissions = document.getElementsByClassName("permissions")[0].children
const returnInfo = new TextResponse("user-addreturn-info")
addButton.addEventListener("click", () => {
var permissionsList = new Array()
for(var permission of permissions) {
console.log(permission.children[0].checked)
if(permission.children[0].checked) {
permissionsList.push(permission.children[0].id.replace("perm_", ""))
}
}
post("US_ADD", {
username: username.value,
display_name: displayname.value,
password: password.value,
picture: picture.files[0],
permissions: permissionsList
}).then((answer) => {
if(answer == "ALREADY_EXIST") {
returnInfo.err("L'utilisateur existe déjà !")
} else if(answer == "USERNAME_MISSING") {
returnInfo.err("Le nom d'utilisateur est manquant !")
} else if(answer == "DISPLAY_NAME_MISSING") {
returnInfo.err("Le nom d'affichage est manquant !")
} else if(answer == "PASSWORD_MISSING") {
returnInfo.err("Le mot de passe est manquant !")
} else {
View.destroyPopup()
loadUsers()
}
})
})
})
users.then(users => {
users = new Map(JSON.parse(users))
for(var user of users) {
user = user[1]
console.log(user)
const userComponent = new User({
username: user.username,
display_name: user.display_name,
picture: user.picture,
permission: user.permission,
window: View,
component: usersComponent
})
usersList.push(userComponent)
}
usersNumber.innerHTML = usersList.length
const usersContent = new Array()
for(var user of usersList) {
usersContent.push(user.generateHTML())
}
usersDiv.innerHTML = usersContent.join("")
for(var user of usersList) {
user.loadScript()
}
})
}
})

View File

@ -213,6 +213,12 @@ a {
user-select: none;
}
.user-actions {
display: flex;
gap: 10px;
}
@media (max-width: 640px) {
.logo {
@ -1051,3 +1057,148 @@ a {
background-color: rgba(44, 40, 42, 0.614);
}
/* USERS */
.us-bar{
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
}
.us-bar p {
font-size: 15px;
}
.user-line {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 10px;
border-radius: 10px;
background-color: #1b1b1bc1;
transition: 0.1s;
align-items: center;
gap: 10px;
}
.user-line-info {
display: flex;
flex-direction: row;
gap: 10px;
align-items: center;
}
.user-line-displayname {
font-size: 15px;
margin-block: 0 !important;
}
.us-users {
display: flex;
padding: 10px;
flex-direction: column;
gap: 10px;
overflow-y: auto ;
height: 700px;
}
.user-edit-actual {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
justify-content: center;
}
.user-edit-line {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.user-edit-info {
font-size: 14px;
}
.user-edit-actions {
display: flex;
flex-direction: row;
gap: 10px;
align-items: space-around;
justify-content: center;
}
.category {
display: flex;
gap: 10px;
flex-direction: column;
align-items: center;
background-color: #1b1b1bc1;
padding: 10px;
margin: 5px;
border-radius: 10px;
}
.permissions {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
font-size: 12px;
gap: 10px;
}
.us-add {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
justify-content: center;
}
.us-add p {
font-size: 14px;
}
.us-edit {
display: flex;
flex-direction: column;
justify-content: center;
gap: 10px;
}
#st-save {
margin-top: 10px;
}
.st-act {
display: flex;
gap: 10px;
}
.us-delete {
font-size: 12px;
}

View File

@ -28,8 +28,10 @@ router.post("/", (req, res) => {
if(token == "AUTH_FAILED") {
res.status(403).send("AUTH_FAILED")
setTimeout(() => {
res.status(403).send("AUTH_FAILED")
}, 1000)
} else {

View File

@ -40,12 +40,15 @@
<script src="/javascripts/basics.js"></script>
<script src="/javascripts/middle.js"></script>
<script src="/javascripts/io.js"></script>
<script src="/javascripts/indexscript.js"></script>
<script src="/javascripts/link.js"></script>
<script src="/javascripts/service.js"></script>
<script src="/javascripts/server.js"></script>
<script src="/javascripts/pipeline.js"></script>
<script src="/javascripts/filexplorer.js"></script>
<script src="/javascripts/indexscript.js"></script>
<script src="/javascripts/user.js"></script>
<script src="/javascripts/metric.js"></script>
<script src="/javascripts/setting.js"></script>
<script src="/javascripts/indexscript.js"></script>
</body>
</html>