diff --git a/bin/files.js b/bin/files.js new file mode 100644 index 0000000..71b5918 --- /dev/null +++ b/bin/files.js @@ -0,0 +1,53 @@ +const { LogType } = require("loguix") +const fs = require("fs") +const path = require("path") +const { __glob } = require("./global-variables") +const clog = new LogType("Fichier") +const os = require("os"); +const uuid = require('uuid'); +var mime = require('mime-types'); + +module.exports.getFiles = function(root) { + + var response = new Object() + response.content = new Array() + response.root = root + response.parent = path.dirname(root) + + + try{ + + if(root == "homepath") { + + root = os.homedir() + response.root = root + + } + + + if(!fs.existsSync(root)) { + response.content = "NOT_EXIST" + + } else { + + for(var file of fs.readdirSync(root)) { + + const stat = fs.statSync(root + path.sep + file) + + response.content.push({"name":file, id: uuid.v4().toString() ,"fileDirectory" : root + path.sep + file , "type":mime.lookup(file), "size":stat.size, "lastedition":stat.mtimeMs, "directory":stat.isDirectory()}) + } + + } + + + + + + }catch(err) { + + response.content = "NOT_PERMITTED" + } + + return response + +} \ No newline at end of file diff --git a/bin/server.js b/bin/server.js index 921d23a..8a702a0 100644 --- a/bin/server.js +++ b/bin/server.js @@ -3,6 +3,7 @@ const fs = require("fs") const path = require("path") const { __glob } = require("./global-variables") const auth = require("./auth") +const files = require("./files") const plog = new LogType("Web") const cook = require("cookie") const http = require("http") @@ -39,7 +40,10 @@ module.exports.serverIO = function(server) { GetAnswer("USERINFO", {username: user.username, display_name: user.display_name ,picture: user.picture, permission: user.permission}) }) - + PostRequest("FX_GET", (root) => { + + PostAnswer("FX_GET", files.getFiles(root)) + }) socket.on("disconnect", () => { @@ -48,7 +52,7 @@ module.exports.serverIO = function(server) { function GetRequest(GQname, GQcallback) { socket.on("GET/" + GQname, () => { - + plog.log(user.username + " - Socket : " + socket.id + " - GET/" + GQname + " - [RECIEVED]") GQcallback() }) @@ -62,6 +66,21 @@ module.exports.serverIO = function(server) { } + function PostRequest(GQname, GQcallback) { + socket.on("POST/" + GQname, (value) => { + plog.log(user.username + " - Socket : " + socket.id + " - POST/" + GQname + " - [RECIEVED]") + GQcallback(value) + }) + + } + + function PostAnswer(GRname, GRvalue) { + + plog.log(user.username + " - Socket : " + socket.id + " - POST/" + GRname + " - [ANSWERED]") + socket.emit("ANSWER/POST/" + GRname, GRvalue) + + } + } else { socket.disconnect() diff --git a/main.js b/main.js index 2834bf8..4c09c35 100644 --- a/main.js +++ b/main.js @@ -2,7 +2,7 @@ const createError = require('http-errors'); const express = require('express'); const path = require('path'); const cookieParser = require('cookie-parser'); -const favicon = require('express-favicon'); +var favicon = require('serve-favicon'); const app = express(); const fs = require("fs"); const log = require("loguix") @@ -48,7 +48,7 @@ function setup() { app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); - app.use(favicon(__glob.ICON)); + app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) getRouters() users.fetchUsers() diff --git a/package-lock.json b/package-lock.json index 32aed08..b7c4b2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,10 +14,10 @@ "debug": "~2.6.9", "ejs": "~2.6.1", "express": "~4.16.1", - "express-favicon": "^2.0.4", "http-errors": "~1.6.3", "loguix": "1.4.1", "nodemon": "^3.0.1", + "serve-favicon": "^2.0.4", "socket.io": "^4.7.2", "uuid": "^9.0.1" } @@ -384,14 +384,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express-favicon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/express-favicon/-/express-favicon-2.0.4.tgz", - "integrity": "sha512-JDGzumJdwF+WcJf+qwyhdpF1yzducuMCxZa+G6hxR3hor7ae/1CqpAPj8FXCGaGtqBA6ExDMfeszjuYRw5GUuQ==", - "engines": { - "node": ">=4" - } - }, "node_modules/express/node_modules/cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", @@ -855,6 +847,31 @@ "node": ">= 0.8.0" } }, + "node_modules/serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", + "dependencies": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-favicon/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/serve-favicon/node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, "node_modules/serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", @@ -1385,11 +1402,6 @@ } } }, - "express-favicon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/express-favicon/-/express-favicon-2.0.4.tgz", - "integrity": "sha512-JDGzumJdwF+WcJf+qwyhdpF1yzducuMCxZa+G6hxR3hor7ae/1CqpAPj8FXCGaGtqBA6ExDMfeszjuYRw5GUuQ==" - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1719,6 +1731,30 @@ "statuses": "~1.4.0" } }, + "serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", + "requires": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, "serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", diff --git a/package.json b/package.json index 464af28..2203eec 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "debug": "~2.6.9", "ejs": "~2.6.1", "express": "~4.16.1", - "express-favicon": "^2.0.4", + "serve-favicon": "^2.0.4", "http-errors": "~1.6.3", "loguix": "1.4.1", "nodemon": "^3.0.1", diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..87d1dc9 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/javascripts/basics.js b/public/javascripts/basics.js index 0d60ba2..f7162ac 100644 --- a/public/javascripts/basics.js +++ b/public/javascripts/basics.js @@ -1,5 +1,8 @@ + + // Get Document ID + /** * Récupère depuis le document l'identifiant de l'élément * @param {string} id Identifiant de l'élément `id='identifiant'` @@ -43,3 +46,223 @@ class InfoPop { } + +const viewsAccessible = new Map() + +var xMousePos = null; +var yMousePos = null; + +document.onmousemove = function(e) { + xMousePos = e.clientX + window.scrollX; + yMousePos = e.clientY + window.scrollY; + +} + +document.oncontextmenu = function(e) { + + xMousePos = e.clientX + window.scrollX; + yMousePos = e.clientY + window.scrollY; + +} + + +class ViewWindow { + ViewHTML = null + ViewProperties =null + ViewSpanInteger = null + constructor(properties) { + if(!viewsAccessible.has(properties.title)) { + + this.ViewProperties = properties + viewsAccessible.set(properties.title, true) + + this.ViewHTML = ` +
+
+ +

${properties.title}

+ +
+
+
+
+ ` + this.ViewSpanInteger = document.createElement("div") + document.body.appendChild(this.ViewSpanInteger); + this.ViewSpanInteger.outerHTML = this.ViewHTML + + const closeWindow = document.getElementById(properties.title + "_close") + closeWindow.addEventListener("click", () => { + + this.destroy() + + }) + + const header = document.getElementById(properties.title + "_header") + const windowDiv = document.getElementById(properties.title + "_window") + + let isDragging = false; + let offsetX, offsetY; + + header.addEventListener('mousedown', (e) => { + isDragging = true; + + // Enregistrez la position de la souris par rapport à la fenêtre + offsetX = e.clientX - windowDiv.getBoundingClientRect().left; + offsetY = e.clientY - windowDiv.getBoundingClientRect().top; + }); + + // Gérer le déplacement + document.addEventListener('mousemove', (e) => { + if (isDragging) { + + header.style.cursor = "grab" + + // Calculez la nouvelle position de la fenêtre en fonction de la position de la souris + const newLeft = e.clientX - offsetX; + const newTop = e.clientY - offsetY; + + // Limitation de la position pour éviter un débordement + const maxX = window.innerWidth - windowDiv.offsetWidth; + const maxY = window.innerHeight - windowDiv.offsetHeight; + + windowDiv.style.left = Math.min(Math.max(newLeft, 0), maxX) + 'px'; + windowDiv.style.top = Math.min(Math.max(newTop, 0), maxY) + 'px'; + } + }); + + // Gérer la fin du glisser-déposer + document.addEventListener('mouseup', () => { + header.style.cursor = "unset" + isDragging = false; + }); + + + + } + + } + + destroy() { + const win = getID(`${this.ViewProperties.title}_window`) + win.outerHTML = "" + viewsAccessible.delete(this.ViewProperties.title) + } + + setContent(text) { + const contentDiv = document.getElementById(this.ViewProperties.title + "_content") + contentDiv.innerHTML = text + } + + getViewTitle() { + + return this.ViewProperties.title + } + +} + +createView("files_explorer") + +function createView(viewType) { + if(viewType == 'files_explorer') { + + generateFileExplorer() + + + } + if(viewType == 'service') { + + const View = new ViewWindow({ + title: "Gestionnaire des services", + width: "1000px", + height: "600px" + }) + } + +} + + +class DroppableMenu { + options = new Array() + id = null + DMSpanInteger = null + constructor(properties) { + + this.id = properties.id + this.options.push(`
`) + + } + + add(action, string) { + + this.options.push("
" + string + "
") + + } + + show() { + + + this.options.push(`
`) + + if(xMousePos && yMousePos) { + + this.DMSpanInteger = document.createElement("span") + document.body.appendChild(this.DMSpanInteger); + this.DMSpanInteger.outerHTML = this.options.join('') + + const menu = getID(`dm-${this.id}`) + + menu.style.left = (xMousePos - 40) + "px" + menu.style.top = (yMousePos - 40) + "px" + + menu.addEventListener('mouseleave', () => { + + menu.outerHTML = "" + + }) + + + } + + + + + } + +} + + + +function getFormattedDate(GetDate) { + + const date = new Date(GetDate) + + var gmonth = date.getMonth() + 1 + var gday = date.getDate() + var gHour = date.getHours() + var gMinute = date.getMinutes() + var gSecondes = date.getSeconds() + + + if(date.getMonth() + 1 < 10) { + gmonth = "0" + (date.getMonth() + 1) + } + + if(date.getDate() + 1 <= 10) { + gday = "0" + date.getDate() + } + + if(date.getHours() + 1 <= 10) { + gHour = "0" + date.getHours() + } + + if(date.getMinutes() + 1 <= 10) { + gMinute = "0" + date.getMinutes() + } + + if(date.getSeconds() + 1 <= 10) { + gSecondes = "0" + date.getSeconds() + } + + return gday + "/" + gmonth + "/" + date.getFullYear() + " - " + gHour + ":" + gMinute +} \ No newline at end of file diff --git a/public/javascripts/filexplorer.js b/public/javascripts/filexplorer.js new file mode 100644 index 0000000..bbe22bf --- /dev/null +++ b/public/javascripts/filexplorer.js @@ -0,0 +1,232 @@ +document.addEventListener("contextmenu", (e) => { + + e.preventDefault() +}) + +function generateFileExplorer() { + + const View = new ViewWindow({ + title: ` Gestionnaire de fichiers`, + width: "1000px", + height: "600px" + }) + + goHomePath() + function goHomePath() { + const rFiles = post("FX_GET", "homepath") + + rFiles.then((result) => { + loadFiles(result) + }) + } + + + + View.setContent(` +
+
+ + +
+ + +
+
+
+
+
+ + `) + + const rootInput = getID(View.getViewTitle() + '_rootInput') + const explorer = getID(View.getViewTitle() + '_explorer') + + rootInput.addEventListener("change", () => { + + const reqFiles = post("FX_GET", rootInput.value) + reqFiles.then((result) => { + loadFiles(result) + + }) + }) + + function loadFiles(files) { + + rootInput.value = files.root + var fileElements = new Array() + + if(files.content == "NOT_PERMITTED") { + fileElements.unshift(`

Revenir au dossier parent

`) + fileElements.push("

Vous n'avez pas les permissions pour accéder à ce dossier.

") + + } else if(files.content == "NOT_EXIST") { + fileElements.unshift(`

Revenir au dossier parent

`) + explorer.innerHTML = "

Ce dossier n'existe pas.

" + } else { + + fileElements.unshift(`

Revenir au dossier parent

`) + for(const file of files.content) { + + // Convert all file.size to a human readable format with units + + file.size = bytesToSize(file.size) + + //Tell if the file is a directory or not + + if(file.directory) { + file.size = "Dossier" + } + + fileElements.push(`
+
+ ${getIcon(file)} +

${file.name}

+
+

Taille : ${file.size}

+

Date de modification : ${getFormattedDate(file.lastedition)}

+
`) + } + + + } + + + explorer.innerHTML = fileElements.join("") + + const parent = document.getElementById("fx-parent") + const home = document.getElementById("fx-home") + + home.addEventListener("click", () => { + + goHomePath() + + }) + + parent.addEventListener("click", () => { + + const reqFiles = post("FX_GET", files.parent) + reqFiles.then((result) => { + loadFiles(result) + }) + + }) + + if(files.content != "NOT_PERMITTED" && files.content != "NOT_EXIST") { + + // If it's a directory, get the file directory and make the request to get the files in it and loadIt + + for(const file of files.content) { + + if(file.directory) { + + const element = document.getElementById(file.id) + element.addEventListener("click", () => { + + const reqFiles = post("FX_GET", file.fileDirectory) + reqFiles.then((result) => { + loadFiles(result) + }) + }) + } + + } + + + } + + } + + + +} + +function createFileMenu(idCreated) { + + const dropMenu = new DroppableMenu({ + "id": idCreated + }) + + dropMenu.add("rename", " Renommer") + dropMenu.add("share", " Partager") + dropMenu.add("delete", " Supprimer") + + + dropMenu.show() +} + +function getIcon(file) { + if(file.type == "application/json") { + + return '' + } + if(file.type == "application/msword" | file.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document") { + + return '' + } + if(file.type == "application/vnd.ms-powerpoint") { + + return '' + } + if(file.type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | file.type == "application/vnd.ms-excel") { + + return '' + } + + if(file.type == "application/java-archive") { + + return '' + } + + if(file.type == "application/x-sh") { + + return '' + } + + if(file.type == "application/x-msdos-program" | file.type == "application/x-msdownload") { + + return'' + } + if(file.type == "application/javascript") { + + return '' + } + if(file.type == "image/png" | file.type == "image/jpeg") { + + return '' + } + if(file.type == "text/html") { + + return '' + } + if(file.type == "text/css") { + + return '' + } + if(file.type == "application/zip") { + + return '' + } + if(file.type == "audio/mpeg") { + + return '' + } + if(file.type == "application/pdf") { + + return '' + } + if(file.directory) { + + return '' + } else { + + return '' + } + +} + +function bytesToSize(bytes) { + var sizes = ['o', 'Ko', 'Mo', 'Go', 'To']; + if (bytes == 0) return '0 o'; + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; +} \ No newline at end of file diff --git a/public/javascripts/indexscript.js b/public/javascripts/indexscript.js index 7859b77..a833d32 100644 --- a/public/javascripts/indexscript.js +++ b/public/javascripts/indexscript.js @@ -19,13 +19,13 @@ REQ_user.then((ANS_user) => { permissions.forEach((permValue) => { if(permValue == "FILES_EXPLORER") { - AvailableViews.push(`
+ AvailableViews.push(`

Gestionnaire de fichiers

`) } if(permValue == "SERVICES") { - AvailableViews.push(`
+ AvailableViews.push(`

Gestion des services

`) diff --git a/public/javascripts/io.js b/public/javascripts/io.js index 8da2865..0adf2f3 100644 --- a/public/javascripts/io.js +++ b/public/javascripts/io.js @@ -36,6 +36,27 @@ function get(request) { } +function post(request, value) { + + return new Promise((resolve, reject) => { + + socket.emit("POST/" + request, value) + console.log("Envoi de la requête POST : " + request) + + socket.once("ANSWER/POST/" + request, (answer) => { + + console.log("Réponse pour la requête : " + request) + + resolve(answer) + + }) + + }) + +} + + + function getSocket() { return socket diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index ec4a17d..1e2046b 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -6,7 +6,7 @@ body { color: white; font-size: 20px; font-family: 'Roboto', sans-serif !important; - + overflow: hidden; } html { @@ -58,6 +58,21 @@ html { text-decoration: none; } +.btn-cover { + color: white; + transition: 0.1s; + cursor: pointer; +} + +.btn-cover:hover { + color: rgba(255, 255, 255, 0.675); + +} + +.btn-cover:active { + + color: rgba(255, 255, 255, 0.575); +} /* Miniaturiez Button */ .min { @@ -404,4 +419,160 @@ a { .view-image { font-size: 72px; -} \ No newline at end of file +} + + +/*ViewWindow*/ + +.view-window { + + position: absolute; + z-index: 1; + background-color: #605e58c1; + backdrop-filter: blur(10px); + border-radius: 0.5vw; + -webkit-user-drag: auto; +} + +.view-window-header { + + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + background-color: rgba(33, 32, 33, 0.753); + border-top-right-radius: 0.5vw; + border-top-left-radius: 0.5vw; + user-select: none; +} + + +/* Files Explorer */ + +.fx-window { + + display: flex; + flex-direction: column; + +} + +.fx-root-input { + background-color: #323031; + border: solid 1px #323031; + border-radius: 0.5vw; + padding: 1%; + color: white; + outline:0px; + width: 100%; + +} + +.fx-explorer { + display: flex; + flex-direction: column; + overflow-y: auto ; + height: 450px; + gap: 20px +} + +.fx-element { + + display: grid; + grid-template-columns: 3fr 1fr 2fr; + grid-column-gap: 10px; + align-items: center; + padding: 5px; + padding-left: 30px; + padding-right: 30px; + font-size: 14px; + transition: 0.1s; +} + +.fx-element div { + display: flex; + justify-content: start; + gap: 10px; + align-items: center; +} + +.fx-element:hover { + + background-color: rgba(44, 40, 42, 0.614); + +} + +.fx-actions { + justify-content: end !important; + width: 100%; +} + +.fx-bar { + + margin: 1%; + display: flex; + gap: 10px; + align-items: center; + +} + +.fx-bar-actions { + + width: 30%; + display: flex; + flex-direction: row; + gap: 10px; + +} + +/* ===== Scrollbar CSS ===== */ + /* Firefox */ + * { + scrollbar-width: auto; + scrollbar-color: #ff5d51 #ffffff; + } + + /* Chrome, Edge, and Safari */ + *::-webkit-scrollbar { + width: 13px; + } + + *::-webkit-scrollbar-track { + background: transparent; + } + + *::-webkit-scrollbar-thumb { + background-color: #ff5d51; + border-radius: 17px; + border: 2px solid transparent; + } + +/* Dropable Menu */ + +.dm-menu { + position: absolute; + display: flex; + flex-direction: column; + width: 150px; + border-radius: 0.5vw; + z-index: 3; + height: auto; +} + + +.dm-element { + + background-color: #1a1819c9; + padding: 10px; + cursor: pointer; + font-size: 14px; + display: grid; + grid-template-columns: 0.2fr 0.8fr; + +} + +.dm-element:hover { + background-color: #ffffffc9; + color:black + +} + diff --git a/views/index.ejs b/views/index.ejs index 49a6df2..6ccb27b 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -56,8 +56,11 @@ - + + + +