V1.0.0.beta-15 Update
All checks were successful
continuous-integration/drone/push Build is passing

Note: We appreciate your feedback and bug reports to continue improving our platform. Thank you for your continued support!
This commit is contained in:
2024-07-26 19:41:22 +02:00
parent 44631acfc6
commit 74850e5a4a
12 changed files with 319 additions and 354 deletions

2
.gitignore vendored
View File

@@ -6,3 +6,5 @@
/file_info.json /file_info.json
/node_modules/ /node_modules/
/data/ /data/
/.idea/
.vscode/

View File

@@ -1,34 +1,48 @@
const fs = require('fs'); const fs = require('fs').promises;
const path = require('path'); const path = require('path');
const { logger, logRequestInfo, ErrorLogger, authLogger } = require('../config/logs'); const { logger, logRequestInfo, ErrorLogger, authLogger } = require('../config/logs');
const debug = require('debug')('app:authMiddleware');
const authMiddleware = async (req, res, next) => { const authMiddleware = async (req, res, next) => {
if (req.isAuthenticated() || (req.session && req.session.user && req.session.user.name)) {
const data = await fs.promises.readFile(path.join(__dirname, '../data', 'user.json'), 'utf8'); try {
const users = JSON.parse(data); if (req.isAuthenticated()) {
const user = users.find(user => user.name === (req.session.user && req.session.user.name));
const data = await fs.readFile(path.join(__dirname, '../data', 'user.json'), 'utf8');
const users = JSON.parse(data);
const sessionUser = req.user;
if (!user) { if (!sessionUser) {
authLogger.info('User is not authenticated and user name is not set'); authLogger.info('Session user is undefined');
return res.redirect('/auth/login'); return res.redirect('/auth/login');
}
if (!sessionUser.id && !sessionUser.name) {
authLogger.info('Session user lacks both id and name');
return res.redirect('/auth/login');
}
const user = users.find(user => user.id === sessionUser.id || user.name === sessionUser.name);
if (!user) {
authLogger.info('User not found in user.json');
return res.redirect('/auth/login');
}
req.session.user = user;
res.locals.user = user;
req.userData = user;
return next();
} else {
authLogger.info(`Authentication failed for IP: ${req.ip}, User Agent: ${req.headers['user-agent']}. Redirecting to login.`);
res.redirect('/auth/login');
}
} catch (error) {
authLogger.error('Error in authentication middleware:', error);
return next(error);
} }
if (!req.session.user) {
authLogger.info('User connection attempt in progress, verification in progress...');
authLogger.info(`Login successfully completed, logged in user is: id=${user.id}, name=${user.name}, role=${user.role}, IP: ${req.ip}, User Agent: ${req.headers['user-agent']}`);
}
res.locals.user = user;
req.session.user = user;
req.userData = user;
return next();
} else {
authLogger.info(`Authentication failed for IP: ${req.ip}, User Agent: ${req.headers['user-agent']}. Redirecting to login.`);
debug('User is not authenticated, redirecting to login...');
res.redirect('/auth/login');
}
}; };
module.exports = authMiddleware; module.exports = authMiddleware;

View File

@@ -1,96 +1,95 @@
const passport = require('passport'); const passport = require('passport');
const DiscordStrategy = require('passport-discord').Strategy; const DiscordStrategy = require('passport-discord').Strategy;
const fs = require('fs'); const fs = require('fs').promises;
const path = require('path'); const path = require('path');
const setupFilePath = path.join(__dirname, '../data', 'setup.json'); const setupFilePath = path.join(__dirname, '../data', 'setup.json');
let setupData; async function loadSetupData() {
try { try {
setupData = JSON.parse(fs.readFileSync(setupFilePath, 'utf-8')); const setupFileContent = await fs.readFile(setupFilePath, 'utf-8');
console.log('Setup data loaded:', setupData); return JSON.parse(setupFileContent);
} catch (err) { } catch (err) {
console.error('Error reading setup.json:', err); console.error('Error reading setup.json:', err);
return null;
}
} }
const callbackURL = `http://${setupData[0].domain}/auth/discord/callback`; async function initializePassport() {
console.log(`Callback URL: ${callbackURL}`); const setupData = await loadSetupData();
passport.use(new DiscordStrategy({ if (!setupData || !setupData[0]) {
clientID: setupData[0].discord.clientID, console.error('Setup data is not loaded or has an incorrect structure.');
clientSecret: setupData[0].discord.clientSecret, return;
callbackURL: callbackURL }
}, (accessToken, refreshToken, profile, done) => {
console.log('Discord profile received:', profile);
fs.readFile(path.join(__dirname, '../data', 'user.json'), 'utf8', (err, data) => { const discordConfig = setupData[0].discord;
if (err) { if (!discordConfig || !discordConfig.clientID || !discordConfig.clientSecret) {
console.error('Error reading user.json:', err); console.error('Discord configuration is missing clientID or clientSecret.');
return done(err); return;
} }
let users; const callbackURL = `http://${setupData[0].domain}/auth/discord/callback`;
passport.use(new DiscordStrategy({
clientID: discordConfig.clientID,
clientSecret: discordConfig.clientSecret,
callbackURL: callbackURL,
scope: ['identify', 'email']
}, async (accessToken, refreshToken, profile, done) => {
try { try {
users = JSON.parse(data); const userFilePath = path.join(__dirname, '../data', 'user.json');
} catch (parseErr) { const data = await fs.readFile(userFilePath, 'utf8');
console.error('Failed to parse user.json:', parseErr); let users = JSON.parse(data);
return done(parseErr);
}
let existingUser = users.find(user => user.id === profile.id); let existingUser = users.find(user => user.id === profile.id);
if (existingUser) { if (existingUser) {
console.log('Existing user found:', existingUser); return done(null, existingUser);
return done(null, existingUser);
}
const newUser = {
id: profile.id,
name: profile.username,
role: "user"
};
users.push(newUser);
fs.writeFile(path.join(__dirname, '../data', 'user.json'), JSON.stringify(users, null, 2), 'utf8', (err) => {
if (err) {
console.error('Error writing to user.json:', err);
return done(err);
} }
console.log('New user created:', newUser);
const newUser = {
id: profile.id,
name: profile.username,
role: "user"
};
users.push(newUser);
await fs.writeFile(userFilePath, JSON.stringify(users, null, 2), 'utf8');
done(null, newUser); done(null, newUser);
});
});
}));
passport.serializeUser((user, done) => { } catch (err) {
console.log('Serializing user:', user); console.error('Error handling user data:', err);
done(null, user.id); done(err);
});
passport.deserializeUser((id, done) => {
fs.readFile(path.join(__dirname, '../data', 'user.json'), 'utf8', (err, data) => {
if (err) {
return done(err);
} }
}));
let users; passport.serializeUser((user, done) => {
console.log('Serializing user:', user);
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try { try {
users = JSON.parse(data); const userFilePath = path.join(__dirname, '../data', 'user.json');
} catch (parseErr) { const data = await fs.readFile(userFilePath, 'utf8');
console.error('Failed to parse user data:', parseErr); const users = JSON.parse(data);
return done(parseErr);
const user = users.find(user => user.id === id);
if (!user) {
return done(null, false, { message: 'User not found.' });
}
done(null, user);
} catch (err) {
console.error('Error deserializing user:', err);
done(err);
} }
const user = users.find(user => user.id === id);
if (!user) {
return done(null, false, { message: 'User not found.' });
}
console.log('Deserializing user:', user);
done(null, user);
}); });
}); }
initializePassport();
module.exports = passport; module.exports = passport;

View File

@@ -1,6 +1,6 @@
{ {
"name": "@cdn-app/insider-myaxrin-labs-dinawo", "name": "@cdn-app/insider-myaxrin-labs-dinawo",
"version": "1.0.0-beta.14", "version": "1.0.0-beta.15",
"description": "", "description": "",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {

View File

@@ -7,6 +7,10 @@ const { getUserData, getSetupData } = require('../../Middlewares/watcherMiddlewa
let setupData; let setupData;
let user; let user;
// Ensure Passport is initialized before using it
router.use(passport.initialize());
router.use(passport.session());
Promise.all([ Promise.all([
getSetupData(), getSetupData(),
getUserData() getUserData()
@@ -15,7 +19,7 @@ Promise.all([
user = userData; user = userData;
if (setupData[0].discord !== undefined) { if (setupData[0].discord !== undefined) {
const DiscordStrategy = require('../../models/Passport-Discord'); require('../../models/Passport-Discord'); // Ensure the strategy is registered
} }
router.get("/auth/discord", (req, res) => { router.get("/auth/discord", (req, res) => {
@@ -33,30 +37,33 @@ Promise.all([
res.redirect('/auth/login'); res.redirect('/auth/login');
} }
}); });
});
router.use(passport.initialize()); router.get('/callback', async (req, res, next) => {
router.use(passport.session()); try {
passport.authenticate('discord', { session: true }, (err, user, info) => {
passport.deserializeUser((user, done) => { if (err) {
done(null, user); console.error('Authentication error:', err);
}); return next(err);
router.get('/callback', passport.authenticate('discord', {
failureRedirect: '/auth/login'
}), (req, res, next) => {
checkUserExistsDiscord(req, res, () => {
if (req.userExists) {
return res.redirect('/dpanel/dashboard');
} else {
createUser(req.user, (createErr) => {
if (createErr) {
return next(createErr);
} }
return res.redirect('/dpanel/dashboard'); if (!user) {
}); console.error('No user found:', info);
return res.redirect('/auth/login');
}
req.logIn(user, (err) => {
if (err) {
console.error('Login error:', err);
return next(err);
}
console.log('Authenticated user:', user);
res.redirect('/dpanel/dashboard');
});
})(req, res, next);
} catch (error) {
console.error('Error handling callback:', error);
next(error);
} }
}); });
}); });

View File

@@ -2,165 +2,45 @@ const express = require('express');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const router = express.Router(); const router = express.Router();
const fileUpload = require('express-fileupload');
const authMiddleware = require('../../../Middlewares/authMiddleware');
const { loggers } = require('winston');
const ncp = require('ncp').ncp;
let configFile = fs.readFileSync(path.join(__dirname, '../../../data', 'setup.json'), 'utf-8')
let config = JSON.parse(configFile)[0];
const bodyParser = require('body-parser');
const crypto = require('crypto');
const os = require('os');
const { getUserData, getSetupData } = require('../../../Middlewares/watcherMiddleware');
let setupData = getSetupData(); router.use(express.json());
let userData = getUserData();
router.use(bodyParser.json());
/** router.post('/wallpaper', (req, res) => {
* @swagger const userId = req.body.userId;
* /dashboard/getfilefolder/{folderName}?token={token}: const wallpaperUrl = req.body.wallpaperUrl;
* post:
* security:
* - bearerAuth: []
* tags:
* - Folder
* summary: Get files and folders in a specific folder
* description: This route allows you to get the files and folders in a specific folder. It requires a valid JWT token in the Authorization header.
* parameters:
* - in: path
* name: folderName
* required: true
* schema:
* type: string
* description: The name of the folder
* - in: header
* name: Authorization
* required: true
* schema:
* type: string
* description: The JWT token of your account to have access
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* type: object
* properties:
* files:
* type: array
* items:
* type: object
* properties:
* name:
* type: string
* type:
* type: string
* 401:
* description: Unauthorized
* content:
* application/json:
* schema:
* type: object
* properties:
* message:
* type: string
* 404:
* description: The specified folder does not exist
* content:
* application/json:
* schema:
* type: object
* properties:
* error:
* type: string
* 500:
* description: Internal server error
* content:
* application/json:
* schema:
* type: object
* properties:
* error:
* type: string
*/
if (!wallpaperUrl) {
function authenticateToken(req, res, next) { return res.status(400).send('No wallpaper URL provided.');
let token = null;
const authHeader = req.headers['authorization'];
if (authHeader) {
token = authHeader.split(' ')[1];
} else if (req.query.token) {
token = req.query.token;
} }
if (token == null) { updateUserWallpaper(userId, wallpaperUrl, res);
if (req.user) {
return next();
} else {
return res.status(401).json({ message: 'Unauthorized' });
}
}
fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => {
if (err) {
console.error('Error reading user.json:', err);
return res.status(401).json({ message: 'Unauthorized' });
}
const users = JSON.parse(data);
const user = users.find(u => u.token === token);
if (user) {
req.user = user;
req.userData = user;
next();
} else {
return res.status(401).json({ message: 'Unauthorized' });
}
});
}
router.get('/wallpaper', authenticateToken, (req, res) => {
fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => {
if (err) {
return res.status(500).send('Error reading the file');
}
const users = JSON.parse(data);
const user = users.find(u => u.token === req.userData.token);
res.json({ wallpaper: user.wallpaper || null });
});
}); });
router.post('/wallpaper', authenticateToken, (req, res) => { const updateUserWallpaper = (userId, wallpaperUrl, res) => {
const newWallpaper = req.body.wallpaper; const userFilePath = path.join(__dirname, '../../../data', 'user.json');
fs.readFile(path.join(__dirname, '../../../data', 'user.json'), 'utf8', (err, data) => { fs.readFile(userFilePath, 'utf8', (err, data) => {
if (err) { if (err) {
return res.status(500).send('Error reading the file'); return res.status(500).send('Error reading the file');
} }
let users = JSON.parse(data); let users = JSON.parse(data);
const userIndex = users.findIndex(u => u.token === req.userData.token);
const userIndex = users.findIndex(u => u.id === userId);
if (userIndex !== -1) { if (userIndex !== -1) {
users[userIndex].wallpaper = newWallpaper; users[userIndex].wallpaper = wallpaperUrl;
fs.writeFile(path.join(__dirname, '../../../data', 'user.json'), JSON.stringify(users, null, 2), (err) => { fs.writeFile(userFilePath, JSON.stringify(users, null, 2), err => {
if (err) { if (err) {
return res.status(500).send('Error writing to the file'); return res.status(500).send('Error writing to the file');
} }
res.send('Wallpaper updated'); res.json({ wallpaper: wallpaperUrl });
}); });
} else { } else {
res.status(401).send('Unauthorized'); res.status(404).send('User not found');
} }
}); });
}); };
module.exports = router; module.exports = router;

View File

@@ -24,6 +24,9 @@ const UpdateSetupAdminRoute = require('./Dpanel/API/Update-Setup-Admin.js');
const DeleteFolderRoute = require('./Dpanel/API/DeleteFolfder.js'); const DeleteFolderRoute = require('./Dpanel/API/DeleteFolfder.js');
const DeleteFileFolderRoute = require('./Dpanel/API/DeleteFileFolder.js'); const DeleteFileFolderRoute = require('./Dpanel/API/DeleteFileFolder.js');
const GetMetaDataFileRoute = require('./Dpanel/API/GetMetaDataFile.js'); const GetMetaDataFileRoute = require('./Dpanel/API/GetMetaDataFile.js');
const BackgroundCustom = require('./Dpanel/API/BackgroundCustom.js');
const ProfilUser = require('./Dpanel/Dashboard/ProfilUser.js');
const PofilPictureRoute = require('./Dpanel/API/ProfilPicture.js');
const loginRoute = require('./Auth/Login.js'); const loginRoute = require('./Auth/Login.js');
const logoutRoute = require('./Auth/Logout.js'); const logoutRoute = require('./Auth/Logout.js');
@@ -50,12 +53,13 @@ router.use('/dpanel/dashboard/admin/users', AdminUsersDpanelRoute);
router.use('/dpanel/dashboard/admin/settingsetup', AdminSettingSetupDpanelRoute) router.use('/dpanel/dashboard/admin/settingsetup', AdminSettingSetupDpanelRoute)
router.use('/dpanel/dashboard/admin/stats-logs', AdminStatsLogsDpanelRoute);; router.use('/dpanel/dashboard/admin/stats-logs', AdminStatsLogsDpanelRoute);;
router.use('/dpanel/dashboard/admin/Privacy-Security', AdminPrivacySecurityDpanelRoute); router.use('/dpanel/dashboard/admin/Privacy-Security', AdminPrivacySecurityDpanelRoute);
router.use('/dpanel/dashboard/profil', ProfilUser);
router.use('/api/dpanel/dashboard/newfolder',discordWebhookSuspisiousAlertMiddleware, logApiRequest, NewFolderRoute); router.use('/api/dpanel/dashboard/newfolder',discordWebhookSuspisiousAlertMiddleware, logApiRequest, NewFolderRoute);
router.use('/api/dpanel/dashboard/rename',discordWebhookSuspisiousAlertMiddleware, logApiRequest, RenameFileRoute); router.use('/api/dpanel/dashboard/rename',discordWebhookSuspisiousAlertMiddleware, logApiRequest, RenameFileRoute);
router.use('/api/dpanel/dashboard/delete',discordWebhookSuspisiousAlertMiddleware, logApiRequest, DeleteFileRoute); router.use('/api/dpanel/dashboard/delete',discordWebhookSuspisiousAlertMiddleware, logApiRequest, DeleteFileRoute);
router.use('/api/dpanel/dashboard/movefile',discordWebhookSuspisiousAlertMiddleware, logApiRequest, MoveFileRoute); router.use('/api/dpanel/dashboard/movefile',discordWebhookSuspisiousAlertMiddleware, logApiRequest, MoveFileRoute);
router.use('/api/dpanel/upload', UploadRoute); router.use('/api/dpanel/upload',discordWebhookSuspisiousAlertMiddleware, logApiRequest, UploadRoute);
router.use('/api/dpanel/dashboard/admin/update-role',discordWebhookSuspisiousAlertMiddleware, logApiRequest, UpdateRoleAdminRoute); router.use('/api/dpanel/dashboard/admin/update-role',discordWebhookSuspisiousAlertMiddleware, logApiRequest, UpdateRoleAdminRoute);
router.use('/api/dpanel/dashboard/admin/update-setup',discordWebhookSuspisiousAlertMiddleware, logApiRequest, UpdateSetupAdminRoute); router.use('/api/dpanel/dashboard/admin/update-setup',discordWebhookSuspisiousAlertMiddleware, logApiRequest, UpdateSetupAdminRoute);
router.use('/api/dpanel/dashboard/deletefolder',discordWebhookSuspisiousAlertMiddleware, logApiRequest, DeleteFolderRoute); router.use('/api/dpanel/dashboard/deletefolder',discordWebhookSuspisiousAlertMiddleware, logApiRequest, DeleteFolderRoute);
@@ -65,6 +69,8 @@ router.use('/api/dpanel/dashboard/backgroundcustom',discordWebhookSuspisiousAler
router.use('/api/dpanel/generate-token',discordWebhookSuspisiousAlertMiddleware, logApiRequest, GenerateTokenRoute); router.use('/api/dpanel/generate-token',discordWebhookSuspisiousAlertMiddleware, logApiRequest, GenerateTokenRoute);
router.use('/api/dpanel/dashboard/getfile', getFileDashboardRoute, logApiRequest); router.use('/api/dpanel/dashboard/getfile', getFileDashboardRoute, logApiRequest);
router.use('/api/dpanel/dashboard/getfilefolder', getFileFolderRoute, logApiRequest); router.use('/api/dpanel/dashboard/getfilefolder', getFileFolderRoute, logApiRequest);
router.use('/api/dpanel/dashboard/backgroundcustom', BackgroundCustom, logApiRequest);
router.use('/api/dpanel/dashboard/profilpicture', PofilPictureRoute, logApiRequest);
router.use('/auth/login', loginRoute); router.use('/auth/login', loginRoute);
router.use('/auth/logout', logoutRoute); router.use('/auth/logout', logoutRoute);

View File

@@ -126,6 +126,9 @@
</style> </style>
<body class="light-mode animate"> <body class="light-mode animate">
<div class="alert alert-primary text-center" role="alert">
Un nouveau look sera bientôt disponible pour la page de connexion. Myaxrin Labs va améliorer son application pour la rendre plus rapide et plus facile à utiliser.
</div>
<div class="container mt-4 animate"> <div class="container mt-4 animate">
<h1 class="title text-center animate">Connexion</h1> <h1 class="title text-center animate">Connexion</h1>
<% if (currentUrl === '/auth/activedirectory' || (setupData[0] && setupData[0].hasOwnProperty('ldap'))) { %> <% if (currentUrl === '/auth/activedirectory' || (setupData[0] && setupData[0].hasOwnProperty('ldap'))) { %>

View File

@@ -21,6 +21,20 @@
</head> </head>
<style>
body {
background-image: url('<%= user.wallpaper %>');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
margin: 0;
height: 100vh;
overflow: hidden;
}
</style>
<body class="light-mode"> <body class="light-mode">
<nav class="navbar navbar-expand-md navbar-light bg-light header"> <nav class="navbar navbar-expand-md navbar-light bg-light header">
<a class="navbar-brand"> <a class="navbar-brand">
@@ -54,21 +68,27 @@
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="btn dropdown-toggle" id="accountDropdownBtn" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="btn dropdown-toggle" id="accountDropdownBtn" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="https://api.dicebear.com/7.x/initials/svg?seed=<%= user.name %>" alt="User Icon" class="rounded-circle" style="width: 30px; height: 30px;" /> <img
src="<%= user.profilePicture || 'https://api.dicebear.com/7.x/initials/svg?seed=' + user.name %>"
alt="User Icon"
class="rounded-circle"
style="width: 30px; height: 30px;"
/>
</a> </a>
<div class="dropdown-menu dropdown-menu-right p-4 bg-dark text-white" id="accountDropdownMenu"> <div class="dropdown-menu dropdown-menu-right p-4 bg-dark text-white" id="accountDropdownMenu">
<div class="mb-3 text-center"> <div class="mb-3 text-center">
<h6 class="text-lg font-semibold"><%= user.name %></h6> <a class="dropdown-item text-center text-white no-hover custom-btn" href="/dpanel/dashboard/profil" id="logoutLink">
<p class="mb-0">ID: <%= user.id %></p> <i class="fas fa-sign-out-alt text-white"></i> Mon profile
<p class="mb-0">Role: <%= user.role %></p> </a>
</div> </div>
<div class="dropdown-divider mb-2"></div> <div class="dropdown-divider mb-2"></div>
<% if (user.role === 'admin') { %> <% if (user.role === 'admin') { %>
<a class="dropdown-item text-center text-white no-hover custom-btn" href="/dpanel/dashboard/admin" id="adminLink"> <a class="dropdown-item text-center text-white no-hover custom-btn" href="/dpanel/dashboard/admin" id="adminLink">
<i class="fas fa-user-shield"></i> Administration du site <i class="fas fa-user-shield"></i> Administration du site
</a> </a><br>
<% } %> <% } %>
<br><br><a class="dropdown-item text-center text-white no-hover custom-btn" href="/auth/logout" id="logoutLink"> <br><a class="dropdown-item text-center text-white no-hover custom-btn" href="/auth/logout" id="logoutLink">
<i class="fas fa-sign-out-alt text-white"></i> Déconnexion <i class="fas fa-sign-out-alt text-white"></i> Déconnexion
</a> </a>
</div> </div>
@@ -76,6 +96,9 @@
</ul> </ul>
</div> </div>
</nav> </nav>
<div class="alert alert-primary text-center" role="alert">
Un nouveau look sera bientôt disponible pour le tableau de bord. Myaxrin Labs va améliorer son application pour la rendre plus rapide et plus facile à utiliser.
</div>
<div class="container mt-4 table-container"> <div class="container mt-4 table-container">
<div class="table-responsive"> <div class="table-responsive">
@@ -164,43 +187,52 @@
<div class="modal fade" id="patchNoteModal" tabindex="-1" role="dialog" aria-labelledby="patchNoteModalLabel" aria-hidden="true"> <div class="modal fade" id="patchNoteModal" tabindex="-1" role="dialog" aria-labelledby="patchNoteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg rounded-lg" role="document"> <div class="modal-dialog modal-lg rounded-lg" role="document">
<div class="modal-content dark-mode"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="patchNoteModalLabel">Patch Note<span class="badge badge-info ml-1">v1.0.0-beta.14</span></h5> <h5 class="modal-title" id="patchNoteModalLabel">Patch Note<span class="badge badge-info ml-1">v1.0.0-beta.15</span></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true">&times;</span>
</button> </button>
</div>
<div class="patch-note-item pl-3">
<p><i class="fas fa-tools"></i> Améliorations :</p>
<ul>
<li>Améliorations mineures et corrections mineures sur tous les niveaux de l'application.<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
<li>Déplacement de fichier d'un dossier à la racine.<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
<li>Suppression chargement login avec la connexion active directory.<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
<li>Modification de la suppression des fichiers à la racine.<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
<li>Modification déplacement fichier sans destination.<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
</ul>
</div>
<div class="patch-note-item pl-3">
<p><i class="fas fa-wrench"></i> Modifications :</p>
<ul>
<li>Correction majeure d'un bug de sécurité.<span class="badge badge-success ml-1">MODIFICATION MAJEURE</span></li>
<li>Modification du message "move file" réponse JSON.<span class="badge badge-success ml-1">MODIFICATION MINEURE</span></li>
</ul>
</div>
<div class="patch-note-item pl-3">
<p>Remarque : Nous apprécions vos retours d'expérience et vos rapports de bogues pour continuer à améliorer notre plateforme. Merci pour votre soutien continu !</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary" onclick="displayMetadata()">Afficher les métadonnées</button>
</div>
</div> </div>
<div class="modal-body">
<div class="patch-note-item">
<p><i class="fas fa-tools"></i> Nouvelles Fonctionnalités :</p>
<ul>
<li>Intégration de l'authentification Discord<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
<li>Personnalisation de l'arrière-plan de l'application<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
<li>Nouveau design pour l'affichage du token dans le panneau administrateur<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
</ul>
</div>
<div class="patch-note-item">
<p><i class="fas fa-wrench"></i> Améliorations :</p>
<ul>
<li>Optimisation des performances de l'application<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
<li>Amélioration de l'interface utilisateur pour une meilleure expérience<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
<li>Mise à jour des dépendances pour une meilleure stabilité<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
</ul>
</div>
<div class="patch-note-item">
<p><i class="fas fa-bug"></i> Corrections de Bugs :</p>
<ul>
<li>Correction des erreurs d'affichage dans certains navigateurs<span class="badge badge-success ml-1">CORRECTION MINEURE</span></li>
</ul>
</div>
<div class="patch-note-item">
<p><i class="fas fa-lock"></i> Sécurité :</p>
<ul>
<li>Renforcement de la sécurité de l'authentification<span class="badge badge-success ml-1">AMÉLIORATION MAJEURE</span></li>
<li>Mise à jour des protocoles de chiffrement<span class="badge badge-success ml-1">AMÉLIORATION MINEURE</span></li>
</ul>
</div>
<p class="note">Remarque : Nous sommes toujours à l'écoute de vos retours pour améliorer notre plateforme. N'hésitez pas à nous faire part de vos commentaires et suggestions !</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Fermer</button>
<button type="button" class="btn btn-primary" onclick="displayMetadata()">Afficher les métadonnées</button>
</div>
</div>
</div> </div>
</div> </div>
@@ -234,7 +266,7 @@
<ul class="nav justify-content-center border-bottom pb-3 mb-3"> <ul class="nav justify-content-center border-bottom pb-3 mb-3">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link px-2 text-muted" href="#" data-toggle="modal" data-target="#patchNoteModal"> <a class="nav-link px-2 text-muted" href="#" data-toggle="modal" data-target="#patchNoteModal">
Version: 1.0.0-beta.14 Version: 1.0.0-beta.15
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -18,6 +18,20 @@
<link rel="icon" href="/public/assets/homelab_logo.png" /> <link rel="icon" href="/public/assets/homelab_logo.png" />
</head> </head>
<style>
body {
background-image: url('<%= user.wallpaper %>');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
margin: 0;
height: 100vh;
overflow: hidden;
}
</style>
<body class="light-mode"> <body class="light-mode">
<nav class="navbar navbar-expand-lg navbar-light bg-light header"> <nav class="navbar navbar-expand-lg navbar-light bg-light header">
<a class="navbar-brand"> <a class="navbar-brand">
@@ -49,6 +63,9 @@
</ul> </ul>
</div> </div>
</nav> </nav>
<div class="alert alert-primary text-center" role="alert">
Un nouveau look sera bientôt disponible pour le tableau de bord. Myaxrin Labs va améliorer son application pour la rendre plus rapide et plus facile à utiliser.
</div>
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb custom-breadcrumb"> <ol class="breadcrumb custom-breadcrumb">
<li class="breadcrumb-item"><a href="/dpanel/dashboard">Accueil</a></li> <li class="breadcrumb-item"><a href="/dpanel/dashboard">Accueil</a></li>
@@ -174,7 +191,7 @@
<div class="container"> <div class="container">
<footer class="py-3 my-4"> <footer class="py-3 my-4">
<ul class="nav justify-content-center border-bottom pb-3 mb-3"> <ul class="nav justify-content-center border-bottom pb-3 mb-3">
<li class="nav-item"><a class="nav-link px-2 text-muted">Version: 1.0.0-beta.14</a></li> <li class="nav-item"><a class="nav-link px-2 text-muted">Version: 1.0.0-beta.15</a></li>
</ul> </ul>
<p class="text-center text-muted">&copy; 2024 Myaxrin Labs</p> <p class="text-center text-muted">&copy; 2024 Myaxrin Labs</p>
</footer> </footer>

View File

@@ -126,55 +126,29 @@
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script> <script>
const body = document.body; document.addEventListener('DOMContentLoaded', function () {
const darkModeSwitch = document.getElementById('darkModeSwitch');
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
document.body.classList.toggle('dark-mode', darkModeMediaQuery.matches);
darkModeMediaQuery.addListener(function (e) {
document.body.classList.toggle('dark-mode', e.matches);
});
});
document.getElementById('themeSwitcher').addEventListener('click', function () { document.getElementById('themeSwitcher').addEventListener('click', function () {
body.classList.toggle('dark-mode'); document.body.classList.toggle('dark-mode');
}); });
document.getElementById('usersPerPage').addEventListener('change', function () { document.getElementById('usersPerPage').addEventListener('change', function () {
window.location.href = "/dpanel/dashboard/admin/users?page=1&limit=" + this.value; window.location.href = "/dpanel/dashboard/admin/users?page=1&limit=" + this.value;
}); });
window.onload = function() { window.onload = function () {
var urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
var limit = urlParams.get('limit'); const limit = urlParams.get('limit');
document.getElementById('usersPerPage').value = limit; document.getElementById('usersPerPage').value = limit;
} }
document.addEventListener('DOMContentLoaded', function () {
const darkModeSwitch = document.getElementById('darkModeSwitch');
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
body.classList.toggle('dark-mode', darkModeMediaQuery.matches);
darkModeMediaQuery.addListener(function (e) {
body.classList.toggle('dark-mode', e.matches);
});
});
function searchUsers() {
var input = document.getElementById('searchInput');
var filter = input.value.toUpperCase();
var table = document.querySelector('.table');
var tr = table.getElementsByTagName('tr');
for (var i = 0; i < tr.length; i++) {
var tdName = tr[i].getElementsByTagName('td')[1];
var tdId = tr[i].getElementsByTagName('td')[0];
if (tdName || tdId) {
var txtValueName = tdName.textContent || tdName.innerText;
var txtValueId = tdId.textContent || tdId.innerText;
if (txtValueName.toUpperCase().indexOf(filter) > -1 || txtValueId.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
document.getElementById('searchButton').addEventListener('click', function (e) { document.getElementById('searchButton').addEventListener('click', function (e) {
e.preventDefault(); e.preventDefault();
searchUsers(); searchUsers();
@@ -187,19 +161,32 @@
} }
}); });
var isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; function searchUsers() {
var searchInput = document.getElementById('searchInput'); const input = document.getElementById('searchInput');
searchInput.placeholder = isMac ? 'Rechercher par nom ou ID (Cmd + K)' : 'Rechercher par nom ou ID (Ctrl + K)'; const filter = input.value.toUpperCase();
const table = document.querySelector('.table');
const tr = table.getElementsByTagName('tr');
for (let i = 0; i < tr.length; i++) {
const tdName = tr[i].getElementsByTagName('td')[1];
const tdId = tr[i].getElementsByTagName('td')[0];
if (tdName || tdId) {
const txtValueName = tdName.textContent || tdName.innerText;
const txtValueId = tdId.textContent || tdId.innerText;
tr[i].style.display = txtValueName.toUpperCase().indexOf(filter) > -1 || txtValueId.toUpperCase().indexOf(filter) > -1 ? "" : "none";
}
}
}
document.getElementById('generate-token-form').addEventListener('submit', function(e) { // Ajout d'un événement pour les formulaires de génération de token
document.querySelectorAll('form[id="generate-token-form"]').forEach(form => {
form.addEventListener('submit', function (e) {
e.preventDefault(); e.preventDefault();
var url = this.getAttribute('action'); const url = this.getAttribute('action');
var method = this.getAttribute('method'); const method = this.getAttribute('method');
const name = this.querySelector('input[name="name"]').value;
var name = this.querySelector('input[name="name"]').value; const id = this.querySelector('input[name="id"]').value;
var id = this.querySelector('input[name="id"]').value; const data = { name: name, id: id };
var data = { name: name, id: id };
fetch(url, { fetch(url, {
method: method, method: method,
@@ -212,7 +199,7 @@
.then(response => { .then(response => {
Swal.fire({ Swal.fire({
title: 'Votre Token', title: 'Votre Token',
html: `<input type="text" id="swal-input1" class="swal2-input" value="${response.token}">`, html: `<input type="text" id="swal-input1" class="swal2-input" value="${response.token}" readonly>`,
confirmButtonText: 'Copier le Token', confirmButtonText: 'Copier le Token',
footer: '<div style="text-align: center;">Gardez ce token en sécurité. Il ne sera pas possible de le récupérer sans le régénérer.</div>', footer: '<div style="text-align: center;">Gardez ce token en sécurité. Il ne sera pas possible de le récupérer sans le régénérer.</div>',
focusConfirm: false, focusConfirm: false,
@@ -226,9 +213,10 @@
}); });
}) })
.catch(error => { .catch(error => {
Swal.fire('Error', error.message, 'error'); Swal.fire('Erreur', error.message, 'error');
}); });
}); });
});
</script> </script>
</body> </body>

View File

@@ -12,7 +12,24 @@
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
</head> </head>
<style>
body {
background-image: url('<%= user.wallpaper %>');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-attachment: fixed;
margin: 0;
height: 100vh;
overflow: hidden;
}
</style>
<body class="light-mode"> <body class="light-mode">
<div class="alert alert-primary text-center" role="alert">
Un nouveau look sera bientôt disponible pour la page de téléversement. Myaxrin Labs va améliorer son application pour la rendre plus rapide et plus facile à utiliser.
</div>
<div class="container mt-4 flex-column"> <div class="container mt-4 flex-column">
<h1 class="mb-4">Upload de Fichiers</h1> <h1 class="mb-4">Upload de Fichiers</h1>
<form id="uploadForm" enctype="multipart/form-data"> <form id="uploadForm" enctype="multipart/form-data">