Version 1.0.1 - Fix de nombreux bugs

This commit is contained in:
2025-05-03 18:26:16 +02:00
parent 812d5c72fa
commit 3aa4201dd2
17 changed files with 760 additions and 199 deletions

View File

@@ -2,9 +2,9 @@
> Cette version est une refonte complète et intégrale de [Subsonics - Web](https://git.raphix.fr/subsonics/web) > Cette version est une refonte complète et intégrale de [Subsonics - Web](https://git.raphix.fr/subsonics/web)
### Bienvenue sur Chopin, la nouvelle version de Subsonics. ## Bienvenue sur Chopin, la nouvelle version de Subsonics
### **Fonctionnalités** ## **Fonctionnalités**
> - Lecture de vidéos depuis Youtube, Spotify et SoundClound > - Lecture de vidéos depuis Youtube, Spotify et SoundClound
> - Lecture de fichiers locaux *(Uniquement sur le site)* > - Lecture de fichiers locaux *(Uniquement sur le site)*
@@ -14,7 +14,6 @@
> - Une interface refaite pour toutes les platformes. > - Une interface refaite pour toutes les platformes.
> - Récupération de vos recommendations & Playlists Spotify / Youtube > - Récupération de vos recommendations & Playlists Spotify / Youtube
Le FrontEnd est gérée par VueJS ✌et le BackEnd a été entièrement refait localement pour des réponses plus rapide et plus stable Le FrontEnd est gérée par VueJS ✌et le BackEnd a été entièrement refait localement pour des réponses plus rapide et plus stable
[CHANGELOG](https://git.raphix.fr/subsonics/chopin/src/branch/main/changelog.md) [CHANGELOG](https://git.raphix.fr/subsonics/chopin/src/branch/main/changelog.md)

6
TODOS.md Normal file
View File

@@ -0,0 +1,6 @@
# List
TODO: Lecture de fichiers depuis le site, nécéssite hébergement.
TODO: Récupération des recommendations, playlists Youtube et Spotify
TODO: Acces à un historique personnel (LOCAL ?)
TODO: Faire un systême de parole.

View File

@@ -1,16 +1,16 @@
{ {
"name": "chopin-backend", "name": "chopin-backend",
"version": "0.4.0", "version": "1.0.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "chopin-backend", "name": "chopin-backend",
"version": "0.4.0", "version": "1.0.1",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@discordjs/voice": "^0.18.0", "@discordjs/voice": "^0.18.0",
"@distube/ytdl-core": "^4.16.8", "@distube/ytdl-core": "^4.16.9",
"@distube/ytsr": "2.0.4", "@distube/ytsr": "2.0.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"discord-player": "^7.1.0", "discord-player": "^7.1.0",
@@ -267,18 +267,18 @@
} }
}, },
"node_modules/@distube/ytdl-core": { "node_modules/@distube/ytdl-core": {
"version": "4.16.8", "version": "4.16.9",
"resolved": "https://registry.npmjs.org/@distube/ytdl-core/-/ytdl-core-4.16.8.tgz", "resolved": "https://registry.npmjs.org/@distube/ytdl-core/-/ytdl-core-4.16.9.tgz",
"integrity": "sha512-Vl04TCOiSSwCFmOHVfzIX117tpT/eCobp2hwx4lo2EyeE70FMVrpQpKSEdh+EjywmVAHs/ZXIsaDy+wq1fMb+g==", "integrity": "sha512-eRYM3lDR1/1ZB+k6jzIdR+8m9VsYEqjz9+DstX1S/aW1f2rlbj22WCdrRbE+sE3DJW8DLJEp69akfjWqQ+nKIw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"http-cookie-agent": "^6.0.8", "http-cookie-agent": "^7.0.1",
"https-proxy-agent": "^7.0.6", "https-proxy-agent": "^7.0.6",
"m3u8stream": "^0.8.6", "m3u8stream": "^0.8.6",
"miniget": "^4.2.3", "miniget": "^4.2.3",
"sax": "^1.4.1", "sax": "^1.4.1",
"tough-cookie": "^5.1.0", "tough-cookie": "^5.1.2",
"undici": "^7.3.0" "undici": "^7.8.0"
}, },
"engines": { "engines": {
"node": ">=20.18.1" "node": ">=20.18.1"
@@ -287,10 +287,34 @@
"url": "https://github.com/distubejs/ytdl-core?sponsor" "url": "https://github.com/distubejs/ytdl-core?sponsor"
} }
}, },
"node_modules/@distube/ytdl-core/node_modules/http-cookie-agent": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-7.0.1.tgz",
"integrity": "sha512-lZHFZUdPTw64PdksQac5xbUd4NWjUbyDYnvR//2sbLpcC4UqEUW0x/6O+rDntVzJzJ07QvhtL5XZSC+c5EK+IQ==",
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.3"
},
"engines": {
"node": ">=20.0.0"
},
"funding": {
"url": "https://github.com/sponsors/3846masa"
},
"peerDependencies": {
"tough-cookie": "^4.0.0 || ^5.0.0",
"undici": "^7.0.0"
},
"peerDependenciesMeta": {
"undici": {
"optional": true
}
}
},
"node_modules/@distube/ytdl-core/node_modules/undici": { "node_modules/@distube/ytdl-core/node_modules/undici": {
"version": "7.3.0", "version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.3.0.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-7.8.0.tgz",
"integrity": "sha512-Qy96NND4Dou5jKoSJ2gm8ax8AJM/Ey9o9mz7KN1bb9GP+G0l20Zw8afxTnY2f4b7hmhn/z8aC2kfArVQlAhFBw==", "integrity": "sha512-vFv1GA99b7eKO1HG/4RPu2Is3FBTWBrmzqzO0mz+rLxN3yXkE4mqRcb8g8fHxzX4blEysrNZLqg5RbJLqX5buA==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=20.18.1" "node": ">=20.18.1"
@@ -3231,30 +3255,6 @@
"license": "ISC", "license": "ISC",
"peer": true "peer": true
}, },
"node_modules/http-cookie-agent": {
"version": "6.0.8",
"resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.8.tgz",
"integrity": "sha512-qnYh3yLSr2jBsTYkw11elq+T361uKAJaZ2dR4cfYZChw1dt9uL5t3zSUwehoqqVb4oldk1BpkXKm2oat8zV+oA==",
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.3"
},
"engines": {
"node": ">=18.0.0"
},
"funding": {
"url": "https://github.com/sponsors/3846masa"
},
"peerDependencies": {
"tough-cookie": "^4.0.0 || ^5.0.0",
"undici": "^5.11.0 || ^6.0.0"
},
"peerDependenciesMeta": {
"undici": {
"optional": true
}
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -6049,21 +6049,21 @@
} }
}, },
"node_modules/tldts": { "node_modules/tldts": {
"version": "6.1.79", "version": "6.1.86",
"resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.79.tgz", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
"integrity": "sha512-wjlYwK8lC/WcywLWf3A7qbK07SexezXjTRVwuPWXHvcjD7MnpPS2RXY5rLO3g12a8CNc7Y7jQRQsV7XyuBZjig==", "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tldts-core": "^6.1.79" "tldts-core": "^6.1.86"
}, },
"bin": { "bin": {
"tldts": "bin/cli.js" "tldts": "bin/cli.js"
} }
}, },
"node_modules/tldts-core": { "node_modules/tldts-core": {
"version": "6.1.79", "version": "6.1.86",
"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.79.tgz", "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz",
"integrity": "sha512-HM+Ud/2oQuHt4I43Nvjc213Zji/z25NSH5OkJskJwHXNtYh9DTRlHMDFhms9dFMP7qyve/yVaXFIxmcJ7TdOjw==", "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
@@ -6115,9 +6115,9 @@
} }
}, },
"node_modules/tough-cookie": { "node_modules/tough-cookie": {
"version": "5.1.1", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
"integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"tldts": "^6.1.32" "tldts": "^6.1.32"

View File

@@ -1,6 +1,6 @@
{ {
"name": "chopin-backend", "name": "chopin-backend",
"version": "1.0.0", "version": "1.0.1",
"description": "Discord Bot for music - Fetching everywhere !", "description": "Discord Bot for music - Fetching everywhere !",
"main": "src/main.js", "main": "src/main.js",
"nodemonConfig": { "nodemonConfig": {
@@ -12,14 +12,16 @@
"delay": "2000000" "delay": "2000000"
}, },
"scripts": { "scripts": {
"start": "nodemon src/main.js" "start": "nodemon src/main.js",
"stop": "ssh raphix@raphix.fr sudo -S -u gitlab-ci pm2 stop 'Subsonics'",
"restart": "ssh raphix@raphix.fr sudo -S -u gitlab-ci pm2 start 'Subsonics'"
}, },
"keywords": [], "keywords": [],
"author": "Raphix", "author": "Raphix",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@discordjs/voice": "^0.18.0", "@discordjs/voice": "^0.18.0",
"@distube/ytdl-core": "^4.16.8", "@distube/ytdl-core": "^4.16.9",
"@distube/ytsr": "2.0.4", "@distube/ytsr": "2.0.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"discord-player": "^7.1.0", "discord-player": "^7.1.0",

View File

@@ -6,6 +6,7 @@ const { LogType } = require("loguix")
const config = require("../utils/Database/Configuration") const config = require("../utils/Database/Configuration")
const metric = require("webmetrik") const metric = require("webmetrik")
const { Player } = require("../player/Player") const { Player } = require("../player/Player")
const {refreshAllUserInformation} = require("../server/auth/User")
const dlog = new LogType("Discord") const dlog = new LogType("Discord")
@@ -37,18 +38,22 @@ function getChannel(guildId, channelId) {
function init() { function init() {
client.once('ready', () => { client.once('ready', async () => {
dlog.log("Connexion au Bot Discord réussi ! Connecté en tant que : " + client.user.tag) dlog.log("Connexion au Bot Discord réussi ! Connecté en tant que : " + client.user.tag)
// Add all guilds to the guilds map // Add all guilds to the guilds map
client.guilds.cache.forEach(guild => { await client.guilds.cache.forEach(async guild => {
guilds.set(guild.id, { var guildMember = await guild.members.fetch()
guildMember = guildMember.map(member => member.user.id)
await guilds.set(guild.id, {
id: guild.id, id: guild.id,
name: guild.name, name: guild.name,
members: guild.members.cache.map(member => member.user.username), members: guildMember,
})
}) })
})
refreshAllUserInformation()
const Activity = require("./Activity") const Activity = require("./Activity")
Activity.idleActivity() Activity.idleActivity()

View File

@@ -62,13 +62,7 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
if(song.type == "spotify") { if(song.type == "spotify") {
song = await spotify.getTracks(song) song = await spotify.getTracks(song)
} }
if(now) { player.readPlaylist(song, now)
player.readPlaylist(song, true)
} else {
player.readPlaylist(song)
}
} else { } else {

View File

@@ -62,13 +62,24 @@ async function getPlaylist(url) {
} }
try { try {
const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/);
// If watch?v= is present in the url with list?=, remove it and the code behind and transform it to playlist?list=
var playlistId;
// Get &list= in the url until the first & or ?
if (url.includes("list=")) {
playlistId = url.match(/(list=)([a-zA-Z0-9_-]+)/);
}
console.log(playlistId);
if (playlistId === null) { if (playlistId === null) {
clog.error("Impossible de récupérer l'identifiant de la playlist YouTube à partir de l'URL"); clog.error("Impossible de récupérer l'identifiant de la playlist YouTube à partir de l'URL");
return null; return null;
} }
const playlistInfo = await ytfps(playlistId[1]); const playlistInfo = await ytfps(playlistId[2]);
if (!playlistInfo) { if (!playlistInfo) {
clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant"); clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant");
@@ -82,8 +93,8 @@ async function getPlaylist(url) {
playlist.title = playlistInfo.title; playlist.title = playlistInfo.title;
playlist.thumbnail = playlistInfo.thumbnail_url; playlist.thumbnail = playlistInfo.thumbnail_url;
playlist.description = playlistInfo.description; playlist.description = playlistInfo.description;
playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`; playlist.url = `https://www.youtube.com/playlist?list=${playlistId[2]}`;
playlist.id = playlistId[1]; playlist.id = playlistId[2];
for (const video of playlistInfo.videos) { for (const video of playlistInfo.videos) {
const song = new Song(); const song = new Song();

View File

@@ -6,7 +6,44 @@ const spotify = require("../media/SpotifyInformation")
const soundcloud = require("../media/SoundcloudInformation") const soundcloud = require("../media/SoundcloudInformation")
async function search(query, multiple) { async function search(query, multiple, forceType) {
if(!query) return null
if(!multiple) multiple = false
if(!forceType) forceType = null
if(forceType == "PLAYLIST") {
if(query.includes("spotify")) {
return await spotify.getPlaylist(query)
} else if(query.includes("soundcloud")) {
return await soundcloud.getPlaylist(query)
} else if(query.includes("youtube")) {
return await youtube.getPlaylist(query)
} else {
return null
}
}
if(forceType == "SONG") {
if(query.includes("spotify")) {
return await spotify.getSong(query)
} else if(query.includes("soundcloud")) {
return await soundcloud.getTrack(query)
} else if(query.includes("youtube")) {
return await youtube.getQuery(query, multiple)
} else {
return null
}
}
if(forceType == "ALBUM") {
if(query.includes("spotify")) {
return await spotify.getAlbum(query)
} else if(query.includes("youtube")) {
return await youtube.getQuery(query, multiple)
} else {
return null
}
}
const type = Resolver.getQueryType(query) const type = Resolver.getQueryType(query)
if(type == QueryType.YOUTUBE_SEARCH) { if(type == QueryType.YOUTUBE_SEARCH) {
return await youtube.getQuery(query, multiple) return await youtube.getQuery(query, multiple)

View File

@@ -127,17 +127,19 @@ class Player {
} }
getState() { getState() {
const playerStatus = this.player?.state?.status ?? false;
const connectionStatus = this.connection?.state?.status ?? false;
const state = { const state = {
current: this.queue.current, current: this.queue.current,
next: this.queue.next, next: this.queue.next,
previous: this.queue.previous, previous: this.queue.previous,
loop: this.loop, loop: this.loop,
shuffle: this.queue.shuffle, shuffle: this.queue.shuffle,
paused: this.player.state.status == AudioPlayerStatus.Paused, paused: playerStatus === AudioPlayerStatus.Paused,
playing: this.player.state.status == AudioPlayerStatus.Playing, playing: playerStatus === AudioPlayerStatus.Playing,
duration: this.getDuration(), duration: this.getDuration(),
playerState: this.player.state.status, playerState: playerStatus,
connectionState: this.connection.state.status, connectionState: connectionStatus,
channelId: this.channelId channelId: this.channelId
} }
return state return state

View File

@@ -14,6 +14,7 @@ class Song {
duration; duration;
readduration; readduration;
type; type;
userAddedId;
constructor(properties) { constructor(properties) {
if(properties) { if(properties) {
@@ -27,6 +28,7 @@ class Song {
this.readduration = properties.readduration ?? this.readduration this.readduration = properties.readduration ?? this.readduration
this.type = properties.type ?? this.type this.type = properties.type ?? this.type
this.authorId = properties.authorId ?? this.authorId this.authorId = properties.authorId ?? this.authorId
} }
} }

View File

@@ -15,7 +15,7 @@ class Playlist {
this.url = url; this.url = url;
this.author = author; this.author = author;
this.authorId = authorId; this.authorId = authorId;
this.songs = songs; this.songs = songs || new Array();
this.thumbnail = thumbnail; this.thumbnail = thumbnail;
this.duration = duration; this.duration = duration;
this.readduration = readduration; this.readduration = readduration;

View File

@@ -9,6 +9,7 @@ const spotify = require('../media/SpotifyInformation');
const playlistDB = new Database("Playlists", __glob.PLAYLISTFILE, {}); const playlistDB = new Database("Playlists", __glob.PLAYLISTFILE, {});
/** /**
* @param {string} id * @param {string} id
* @param {string} name * @param {string} name
@@ -20,7 +21,7 @@ function getPlaylistsOfUser(id) {
return playlistDB.data[id]; return playlistDB.data[id];
} else { } else {
// Creaete a key with the user id and an empty array // Creaete a key with the user id and an empty array
playlistDB.data;[id] = new Array(); playlistDB.data[id] = new Array();
clog.log(`Création d'une clé pour l'utilisateur : ${id}`); clog.log(`Création d'une clé pour l'utilisateur : ${id}`);
playlistDB.save(); playlistDB.save();
return playlistDB.data[id]; return playlistDB.data[id];
@@ -35,7 +36,7 @@ function getPlaylistsOfUser(id) {
*/ */
function getPlaylistOfUser(id, name) { function getPlaylistOfUser(id, name) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const playlist = playlists.find(p => p.name === name); const playlist = playlists.find(p => p.title === name);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`);
return null; return null;
@@ -46,12 +47,16 @@ function getPlaylistOfUser(id, name) {
async function addPlaylist(id, name, url) { async function addPlaylist(id, name, url) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
var playlist = new Playlist(name, url); var playlist = new Playlist(name, url);
if (playlists.find(p => p.name === name)) { if (playlists.find(p => p.title === name)) {
clog.warn(`La playlist ${name} existe déjà pour l'utilisateur ${id}`); clog.warn(`La playlist ${name} existe déjà pour l'utilisateur ${id}`);
return; return;
} }
var failed;
if(url) { if(url) {
await Finder.search(url).then(async (playlistFounded) => { await Finder.search(url, false, "PLAYLIST").then(async (playlistFounded) => {
if(!playlistFounded) {
failed = true;
}
if(playlistFounded instanceof Playlist) { if(playlistFounded instanceof Playlist) {
playlist = playlistFounded; playlist = playlistFounded;
} }
@@ -61,6 +66,11 @@ async function addPlaylist(id, name, url) {
}) })
} }
if(failed) {
clog.error(`Impossible de trouver la playlist ${name} pour l'utilisateur ${id}`);
return null;
}
playlists.push(playlist); playlists.push(playlist);
playlistDB.save(); playlistDB.save();
clog.log(`Ajout de la playlist ${name} pour l'utilisateur ${id}`); clog.log(`Ajout de la playlist ${name} pour l'utilisateur ${id}`);
@@ -69,7 +79,7 @@ async function addPlaylist(id, name, url) {
function removePlaylist(id, name) { function removePlaylist(id, name) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const index = playlists.findIndex(p => p.name === name); const index = playlists.findIndex(p => p.title === name);
if (index === -1) { if (index === -1) {
clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`);
return; return;
@@ -80,7 +90,7 @@ function removePlaylist(id, name) {
} }
function getPlaylist(id, name) { function getPlaylist(id, name) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const playlist = playlists.find(p => p.name === name); const playlist = playlists.find(p => p.title === name);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${id}`);
return null; return null;
@@ -90,38 +100,66 @@ function getPlaylist(id, name) {
function copyPlaylist(fromId, toId, name) { function copyPlaylist(fromId, toId, name) {
const playlists = getPlaylistsOfUser(fromId); const playlists = getPlaylistsOfUser(fromId);
const playlist = playlists.find(p => p.name === name); const playlist = playlists.find(p => p.title === name);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${fromId}`); clog.warn(`La playlist ${name} n'existe pas pour l'utilisateur ${fromId}`);
return null; return null;
} }
const toPlaylists = getPlaylistsOfUser(toId); const toPlaylists = getPlaylistsOfUser(toId);
// Check if the playlist already exists in the target user
if (toPlaylists.find(p => p.title === name)) {
clog.warn(`La playlist ${name} existe déjà pour l'utilisateur ${toId}`);
return null;
}
toPlaylists.push(playlist); toPlaylists.push(playlist);
playlistDB.save(); playlistDB.save();
clog.log(`Copie de la playlist ${name} de l'utilisateur ${fromId} vers l'utilisateur ${toId}`); clog.log(`Copie de la playlist ${name} de l'utilisateur ${fromId} vers l'utilisateur ${toId}`);
return newPlaylist; return false;
} }
function renamePlaylist(id, oldName, newName) { function renamePlaylist(id, oldName, newName) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const playlist = playlists.find(p => p.name === oldName); const playlist = playlists.find(p => p.title === oldName);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${oldName} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${oldName} n'existe pas pour l'utilisateur ${id}`);
return null; return null;
} }
playlist.name = newName; // Check if the new name already exists
if (playlists.find(p => p.title === newName)) {
clog.warn(`La playlist ${newName} existe déjà pour l'utilisateur ${id}`);
return null;
}
playlist.title = newName;
playlistDB.save(); playlistDB.save();
clog.log(`Renommage de la playlist ${oldName} en ${newName} pour l'utilisateur ${id}`); clog.log(`Renommage de la playlist ${oldName} en ${newName} pour l'utilisateur ${id}`);
} }
function addSong(id, playlistName, song) { function addSong(id, playlistName, song) {
if(typeof song === "string") {
try {
song = JSON.parse(song)
} catch (e) {
clog.error(`La chanson ${song} n'est pas valide`);
return null;
}
}
// Check if the song is a valid object
if (typeof song !== 'object' || !song) {
clog.error(`La chanson ${song} n'est pas valide`);
return null;
}
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const playlist = playlists.find(p => p.name === playlistName); const playlist = playlists.find(p => p.title === playlistName);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${playlistName} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${playlistName} n'existe pas pour l'utilisateur ${id}`);
return null; return null;
} }
// Check the integrity of the song
if (!song.id || !song.title || !song.url) {
clog.error(`La chanson ${song.title} n'est pas valide`);
return null;
}
playlist.songs.push(song); playlist.songs.push(song);
playlistDB.save(); playlistDB.save();
clog.log(`Ajout de la chanson ${song.title} à la playlist ${playlistName} pour l'utilisateur ${id}`); clog.log(`Ajout de la chanson ${song.title} à la playlist ${playlistName} pour l'utilisateur ${id}`);
@@ -129,7 +167,7 @@ function addSong(id, playlistName, song) {
function removeSong(id, playlistName, songId) { function removeSong(id, playlistName, songId) {
const playlists = getPlaylistsOfUser(id); const playlists = getPlaylistsOfUser(id);
const playlist = playlists.find(p => p.name === playlistName); const playlist = playlists.find(p => p.title === playlistName);
if (!playlist) { if (!playlist) {
clog.warn(`La playlist ${playlistName} n'existe pas pour l'utilisateur ${id}`); clog.warn(`La playlist ${playlistName} n'existe pas pour l'utilisateur ${id}`);
return null; return null;

View File

@@ -1,6 +1,7 @@
const {LogType} = require('loguix') const {LogType} = require('loguix')
const wlog = new LogType("Server") const wlog = new LogType("Server")
const path = require("path")
const {Server} = require('socket.io') const {Server} = require('socket.io')
const {createServer} = require('http') const {createServer} = require('http')
const session = require("../server/auth/Session") const session = require("../server/auth/Session")
@@ -21,6 +22,7 @@ const { restart } = require('../utils/Maintenance')
const allConnectedUsers = new Array() const allConnectedUsers = new Array()
const guildConnectedUsers = new Map() const guildConnectedUsers = new Map()
const UsersBySocket = new Map()
function init() { function init() {
@@ -37,11 +39,11 @@ function init() {
process.on("PLAYERS_UPDATE", () => { process.on("PLAYERS_UPDATE", () => {
if(io) { if(io) {
// Get all players and send them to client subscribed to the guild // Get all players and send them to client subscribed to the guild
for(var guild of discordBot.getGuilds()) { for(var guild of discordBot.getGuilds().keys()) {
const player = players.getPlayer(guild.id) const player = players.getPlayer(guild)
if(player) { if(player) {
io.to(guild.id).emit("PLAYER_UPDATE", player.getState()) io.to(player.guildId).emit("/PLAYER/UPDATE", player.getState())
wlog.log("Envoi de l'état du player de la guilde : " + guild.id + " à tous les utilisateurs connectés") wlog.log("Envoi de l'état du player de la guilde : " + player.guildId + " à tous les utilisateurs connectés")
} }
} }
} }
@@ -50,23 +52,38 @@ function init() {
process.on("USERS_UPDATE", () => { process.on("USERS_UPDATE", () => {
if(io) { if(io) {
// Get all players and send them to client subscribed to the guild // Get all players and send them to client subscribed to the guild
for(var guild of discordBot.getGuilds()) { for(var guild of discordBot.getGuilds().keys()) {
if(guildConnectedUsers.has(guild.id)) { if(guildConnectedUsers.has(guild)) {
io.sockets.emit("USERS_UPDATE", guildConnectedUsers.get(guild.id)) io.to(guild).emit("/USERS/UPDATE", {"id": guild, "members": guildConnectedUsers.get(guild)} )
io.to("admin").emit("ALL_USERS_UPDATE", allConnectedUsers) io.to("ADMIN").emit("ALL_USERS_UPDATE", allConnectedUsers)
wlog.log("Envoi de la liste des utilisateurs connectés à la guilde : " + guild.id + " à tous les utilisateurs connectés") wlog.log("Envoi de la liste des utilisateurs connectés (" + guildConnectedUsers.get(guild).length +") à la guilde : " + guild + " à tous les utilisateurs connectés")
} }
} }
} }
}) })
io.on("connection", async (socket) => { io.on("connection", async (socket) => {
var socketUser;
// Make sure Discord Bot is loaded and make an interruption until it is loaded
while(!discordBot.getClient().isReady()) {
wlog.warn("Attente de traitement : "+ socket.id + " : Le bot Discord n'est pas encore chargé, attente de 1 seconde...")
await new Promise(resolve => setTimeout(resolve, 1000))
}
wlog.log(`Connexion d'un client : ${socket.id}`) wlog.log(`Connexion d'un client : ${socket.id}`)
socket.on("disconnect", () => {
handleDisconnect()
wlog.log("Déconnexion du client : " + socket.id)
})
socket.on("error", (error) => {
handleDisconnect()
wlog.error("Erreur sur le socket : " + socket.id + " - " + error)
})
if(socket.handshake.auth == undefined || socket.handshake.auth == {}) { if(socket.handshake.auth == undefined || socket.handshake.auth == {}) {
wlog.warn("Authentification manquant pour le client :" + socket.id) wlog.warn("Authentification manquant pour le client :" + socket.id)
sendSession() sendSession()
@@ -79,7 +96,7 @@ function init() {
if(sessionId) { if(sessionId) {
if(!session.checkSession(sessionId)) { if(!session.checkSession(sessionId)) {
wlog.warn("Session invalide pour le client :" + socket.id) wlog.warn("Session invalide pour le client : " + socket.id)
sendSession() sendSession()
return; return;
} else { } else {
@@ -87,19 +104,18 @@ function init() {
const discordUser = await discordAuth.getDiscordUser(sessionId, auth_code) const discordUser = await discordAuth.getDiscordUser(sessionId, auth_code)
session.removeSession(sessionId) session.removeSession(sessionId)
if(discordUser == "GUILDS_ERROR" || discordUser == "USER_INFO_ERROR" || discordUser == "ACCESS_TOKEN_ERROR") { if(discordUser == "GUILDS_ERROR" || discordUser == "USER_INFO_ERROR" || discordUser == "ACCESS_TOKEN_ERROR") {
wlog.warn("Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId) wlog.warn("Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId)
socket.emit("AUTH_ERROR") socket.emit("AUTH_ERROR", discordUser)
socket.disconnect() socket.disconnect()
return return
} else { } else {
const loggedUser = users.addUser(discordUser.auth, discordUser.identity, discordUser.guilds) const loggedUser = await users.addUser(discordUser.auth, discordUser.identity, discordUser.guilds)
for(var guild of discordUser.guilds) { for(var guild of discordUser.guilds) {
if(guild.owner) { if(guild.owner) {
users.setGuildOwner(loggedUser.identity.id, guild.id) users.setGuildOwner(loggedUser.identity.id, guild.id, true)
} }
} }
const newToken = loggedUser.createToken() const newToken = await loggedUser.createToken()
socket.emit("NEW_TOKEN", newToken) socket.emit("NEW_TOKEN", newToken)
socket.disconnect() socket.disconnect()
wlog.log("Utilisateur Discord associé à la session : " + sessionId + " récupéré avec succès") wlog.log("Utilisateur Discord associé à la session : " + sessionId + " récupéré avec succès")
@@ -109,6 +125,8 @@ function init() {
} else { } else {
wlog.warn("Code d'authentification manquant pour le client :" + socket.id) wlog.warn("Code d'authentification manquant pour le client :" + socket.id)
socket.disconnect()
return
} }
} }
} }
@@ -119,47 +137,81 @@ function init() {
return return
} }
const socketUser = users.getUserByToken(token) socketUser = users.getUserByToken(token)
if(!socketUser) { if(!socketUser) {
wlog.warn("Token invalide pour le client :" + socket.id) wlog.warn("Token invalide pour le client :" + socket.id)
sendSession() sendSession()
return return
} else {
if(!socketUser.auth) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'a pas d'authentification Discord Valide")
socketUser.clearToken()
socket.emit("AUTH_ERROR", "AUTH_ERROR")
socket.disconnect()
return
} }
await users.updateGuilds(socketUser.identity.id)
await users.updateIdentity(socketUser.identity.id)
}
socketUser = users.getUserByToken(token)
if(socketUser) { if(socketUser) {
if(allConnectedUsers.includes(socketUser.identity.id)) { if(allConnectedUsers.includes(socketUser.identity.id)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est déjà connecté sur un autre appareil") wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est déjà connecté sur un autre appareil")
return return
} else { } else {
allConnectedUsers.push(socketUser.identity) allConnectedUsers.push(socketUser.identity)
addGuildConnectedUser(socketUser.identity, socketUser.guilds) addGuildConnectedUser(socketUser.identity, socketUser.guilds)
process.emit("USERS_UPDATE") UsersBySocket.set(socketUser.identity.id, socket.id)
} }
wlog.log("Utilisateur connecté : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) wlog.log("Utilisateur connecté : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
process.emit("USERS_UPDATE")
if(socketUser.isFullBanned()) { if(socketUser.isFullBanned()) {
wlog.warn("Utilisateur banni : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id) wlog.warn("Utilisateur banni : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
socket.emit("BANNED") socket.emit("BANNED")
socket.disconnect() socket.disconnect()
} }
if(socketUser.labels.includes("admin")) { if(socketUser.isAdmin()) {
socket.join("admin") socket.join("ADMIN")
wlog.log("Utilisateur admin identifié : " + socketUser.identity.username + " (" + socketUser.identity.id + ")") wlog.log("Utilisateur admin identifié : " + socketUser.identity.username + " (" + socketUser.identity.id + ")")
} }
// USERS // USERS
// CHECKED : 24/04/2025
IORequest("/USER/INFO", () => { IORequest("/USER/INFO", () => {
var guildPresents = new Array();
var guildsOfBot = discordBot.getGuilds()
for(var guild of guildsOfBot) {
if(guild[1].members.includes(socketUser.identity.id)) {
guildPresents.push(guild[1].id)
}
}
IOAnswer("/USER/INFO", { IOAnswer("/USER/INFO", {
identity: socketUser.identity, identity: socketUser.identity,
guilds: socketUser.guilds, guilds: guildPresents,
labels: socketUser.labels labels: socketUser.labels,
}) })
wlog.log("Envoi des informations Discord de '" + socketUser.identity.id + "' à '" + socket.id + "'" ) wlog.log("Envoi des informations Discord de '" + socketUser.identity.id + "' à '" + socket.id + "'" )
}) })
//CHECKED : 24/04/2025
IORequest("/USER/SIGNOUT", () => {
socketUser.removeToken(token)
socket.disconnect()
})
// CHECKED : 24/04/2025
IORequest("/USERS/LIST", (guildId) => { IORequest("/USERS/LIST", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return if(!checkUserGuild(socketUser, guildId)) return
if(!guildConnectedUsers.has(guildId)) return IOAnswer("/USERS/LIST", false) if(!guildConnectedUsers.has(guildId)) return IOAnswer("/USERS/LIST", false)
@@ -171,25 +223,26 @@ function init() {
IORequest("/PLAYER/PREVIOUS/LIST", (guildId) => { IORequest("/PLAYER/PREVIOUS/LIST", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return if(!checkUserGuild(socketUser, guildId)) return
const list = new List(guildId) const list = new List(guildId)
return list.getPrevious() IOAnswer("/PLAYER/PREVIOUS/LIST", list.getPrevious())
}) })
//TODO: Faire les autres reqêtes sur la liste
IORequest("/PLAYER/JOIN", (guildId) => { IORequest("/PLAYER/JOIN", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return if(!checkUserGuild(socketUser, guildId)) return
wlog.log("L'utilisateur '" + socketUser.identity.username + "' rejoint la liste d'écoute du player de la guilde : " + guildId) wlog.log("L'utilisateur '" + socketUser.identity.username + "' rejoint la liste d'écoute du player de la guilde : " + guildId)
// Make him to leave all the other rooms except the ADMIN room if he is admin
socket.rooms.forEach((room) => {
if(room != "ADMIN") {
socket.leave(room)
}
})
socket.join(guildId) socket.join(guildId)
IOAnswer("PLAYER_STATE", true) IOAnswer("PLAYER_STATE", true)
}) })
IORequest("/PLAYER/LEAVE", (guildId) => {
if(!checkUserGuild(socketUser, guildId)) return
wlog.log("L'utilisateur '" + socketUser.identity.username + "' quitte la liste d'écoute du player de la guilde : " + guildId)
socket.leave(guildId)
IOAnswer("PLAYER_STATE", false)
})
IORequest("/PLAYER/STATE", (guildId) => { IORequest("/PLAYER/STATE", (guildId) => {
handlePlayerAction(guildId, (player) => player.getState(), "/PLAYER/STATE"); handlePlayerAction(guildId, async (player) => await player.getState(), "/PLAYER/STATE");
}) })
IORequest("/PLAYER/PAUSE", (guildId) => { IORequest("/PLAYER/PAUSE", (guildId) => {
@@ -227,7 +280,11 @@ function init() {
}, "/PLAYER/CHANNEL/CHANGE"); }, "/PLAYER/CHANNEL/CHANGE");
}); });
IORequest("/PLAYER/SEEK", (guildId, time) => { IORequest("/PLAYER/SEEK", (data) => {
if(!data) return IOAnswer("/PLAYER/SEEK", false)
const {guildId, time} = data
if(!guildId) return IOAnswer("/PLAYER/SEEK", false)
if(!time) return IOAnswer("/PLAYER/SEEK", false)
handlePlayerAction(guildId, (player) => { handlePlayerAction(guildId, (player) => {
// Check if current is not null // Check if current is not null
if(player.queue.current == null) { if(player.queue.current == null) {
@@ -239,7 +296,11 @@ function init() {
}, "/PLAYER/SEEK"); }, "/PLAYER/SEEK");
}); });
IORequest("/QUEUE/PLAY/NOW", (guildId, listType, index) => { IORequest("/QUEUE/PLAY/NOW", (data) => {
if(!data) return IOAnswer("/QUEUE/PLAY/NOW", false)
const {guildId, song} = data
if(!song) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!guildId) return IOAnswer("/QUEUE/PLAY/NOW", false)
if(!checkUserGuild(socketUser, guildId)) return if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId) const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/QUEUE/PLAY", false) if(!connectToPlayer(guildId, player)) return IOAnswer("/QUEUE/PLAY", false)
@@ -255,7 +316,11 @@ function init() {
IOAnswer("/QUEUE/PLAY/NOW", true) IOAnswer("/QUEUE/PLAY/NOW", true)
}) })
IORequest("/QUEUE/NEXT/DELETE", (guildId, index) => { IORequest("/QUEUE/NEXT/DELETE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/DELETE", false)
const {guildId, index} = data
if(!guildId) return IOAnswer("/QUEUE/NEXT/DELETE", false)
if(!index) return IOAnswer("/QUEUE/NEXT/DELETE", false)
handlePlayerAction(guildId, (player) => { handlePlayerAction(guildId, (player) => {
const next = player.queue.getNext() const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/DELETE", false); if(!next[index]) return IOAnswer("/QUEUE/NEXT/DELETE", false);
@@ -267,7 +332,12 @@ function init() {
handlePlayerAction(guildId, (player) => player.queue.clearNext()) handlePlayerAction(guildId, (player) => player.queue.clearNext())
}) })
IORequest("/QUEUE/NEXT/MOVE", (guildId, index, newIndex) => { IORequest("/QUEUE/NEXT/MOVE", (data) => {
if(!data) return IOAnswer("/QUEUE/NEXT/MOVE", false)
const {guildId, index, newIndex} = data
if(!guildId) return IOAnswer("/QUEUE/NEXT/MOVE", false)
if(!index) return IOAnswer("/QUEUE/NEXT/MOVE", false)
if(!newIndex) return IOAnswer("/QUEUE/NEXT/MOVE", false)
handlePlayerAction(guildId, (player) => { handlePlayerAction(guildId, (player) => {
const next = player.queue.getNext() const next = player.queue.getNext()
if(!next[index]) return IOAnswer("/QUEUE/NEXT/MOVE", false); if(!next[index]) return IOAnswer("/QUEUE/NEXT/MOVE", false);
@@ -277,11 +347,16 @@ function init() {
// SEARCH // SEARCH
// CHECKED : 24/04/2025
IORequest("/SEARCH", async (query) => { IORequest("/SEARCH", async (query) => {
IOAnswer("/SEARCH", await Finder.search(query)) IOAnswer("/SEARCH", await Finder.search(query, true))
}) })
IORequest("/SEARCH/PLAY", async (guildId, song, now) => { IORequest("/SEARCH/PLAY", async (data) => {
if(!data) return IOAnswer("/SEARCH/PLAY", false)
const {guildId, song, now} = data
if(!song) return IOAnswer("/SEARCH/PLAY", false)
if(!guildId) return IOAnswer("/SEARCH/PLAY", false)
if(!checkUserGuild(socketUser, guildId)) return if(!checkUserGuild(socketUser, guildId)) return
const player = new Player(guildId) const player = new Player(guildId)
if(!connectToPlayer(guildId, player)) return IOAnswer("/SEARCH/PLAY", false) if(!connectToPlayer(guildId, player)) return IOAnswer("/SEARCH/PLAY", false)
@@ -296,25 +371,36 @@ function init() {
// PLAYLISTS // PLAYLISTS
IORequest("/PLAYLISTS/CREATE", (name, url) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/CREATE", async (data) => {
if(!data) return IOAnswer("/PLAYLISTS/CREATE", false)
const {name, url} = data
if(!name) return IOAnswer("/PLAYLISTS/CREATE", false) if(!name) return IOAnswer("/PLAYLISTS/CREATE", false)
const playlist = playlists.addPlaylist(socketUser.identity.id, name, url) const playlist = await playlists.addPlaylist(socketUser.identity.id, name, url)
if(!playlist) return IOAnswer("/PLAYLISTS/CREATE", false) if(!playlist) return IOAnswer("/PLAYLISTS/CREATE", false)
IOAnswer("/PLAYLISTS/CREATE", true) IOAnswer("/PLAYLISTS/CREATE", true)
}) })
IORequest("/PLAYLISTS/DELETE", (name) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/DELETE", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/DELETE", false)
const {name} = data
if(!name) return IOAnswer("/PLAYLISTS/DELETE", false) if(!name) return IOAnswer("/PLAYLISTS/DELETE", false)
playlists.removePlaylist(socketUser.identity.id, name) playlists.removePlaylist(socketUser.identity.id, name)
IOAnswer("/PLAYLISTS/DELETE", true) IOAnswer("/PLAYLISTS/DELETE", true)
}) })
// CHECKED : 24/04/2025
IORequest("/PLAYLISTS/LIST", () => { IORequest("/PLAYLISTS/LIST", () => {
const playlist = playlists.getPlaylistsOfUser(socketUser.identity.id) const playlist = playlists.getPlaylistsOfUser(socketUser.identity.id)
IOAnswer("/PLAYLISTS/LIST", playlist) IOAnswer("/PLAYLISTS/LIST", playlist)
}) })
IORequest("/PLAYLISTS/SEND", (name, toId) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/SEND", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/SEND", false)
const {name, toId} = data
if(!name || !toId) return IOAnswer("/PLAYLISTS/SEND", false)
// Check if toId is in the same guilds as the user // Check if toId is in the same guilds as the user
// Check if the toId exists and have a playlist with the same name // Check if the toId exists and have a playlist with the same name
const toUser = users.getUserById(toId) const toUser = users.getUserById(toId)
@@ -327,7 +413,10 @@ function init() {
IOAnswer("/PLAYLISTS/SEND", true) IOAnswer("/PLAYLISTS/SEND", true)
}) })
IORequest("/PLAYLISTS/RENAME", (name, newName) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/RENAME", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/RENAME", false)
const {name, newName} = data
if(!name || !newName) return IOAnswer("/PLAYLISTS/RENAME", false) if(!name || !newName) return IOAnswer("/PLAYLISTS/RENAME", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/RENAME", false) if(!playlist) return IOAnswer("/PLAYLISTS/RENAME", false)
@@ -335,21 +424,33 @@ function init() {
IOAnswer("/PLAYLISTS/RENAME", true) IOAnswer("/PLAYLISTS/RENAME", true)
}) })
IORequest("/PLAYLISTS/ADD_SONG", (name, song) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/ADD_SONG", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
const {name, song} = data
if(!name || !song) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/ADD_SONG", false) if(!playlist) return IOAnswer("/PLAYLISTS/ADD_SONG", false)
playlists.addSong(socketUser.identity.id, name, song) playlists.addSong(socketUser.identity.id, name, song)
IOAnswer("/PLAYLISTS/ADD_SONG", true) IOAnswer("/PLAYLISTS/ADD_SONG", true)
}) })
IORequest("/PLAYLISTS/REMOVE_SONG", (name, songId) => { // CHECKED : 30/04/2025
IORequest("/PLAYLISTS/REMOVE_SONG", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
const {name, songId} = data
if(!name || !songId) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false) if(!playlist) return IOAnswer("/PLAYLISTS/REMOVE_SONG", false)
playlists.removeSong(socketUser.identity.id, name, songId) playlists.removeSong(socketUser.identity.id, name, songId)
IOAnswer("/PLAYLISTS/REMOVE_SONG", true) IOAnswer("/PLAYLISTS/REMOVE_SONG", true)
}) })
IORequest("/PLAYLISTS/PLAY", (guildId, name, now) => { IORequest("/PLAYLISTS/PLAY", (data) => {
if(!data) return IOAnswer("/PLAYLISTS/PLAY", false)
const {name, guildId, now} = data
if(!name || !guildId) return IOAnswer("/PLAYLISTS/PLAY", false)
if(!checkUserGuild(socketUser, guildId)) return IOAnswer("/PLAYLISTS/PLAY", false)
const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name) const playlist = playlists.getPlaylistOfUser(socketUser.identity.id, name)
if(!playlist) return IOAnswer("/PLAYLISTS/PLAY", false) if(!playlist) return IOAnswer("/PLAYLISTS/PLAY", false)
const player = new Player(guildId) const player = new Player(guildId)
@@ -361,8 +462,10 @@ function init() {
// ADMIN // ADMIN
if(socketUser.labels.includes("admin")) { if(socketUser.isAdmin()) {
// CHECKED : 24/04/2025
IORequest("/ADMIN/LOGS", () => { IORequest("/ADMIN/LOGS", () => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/LOGS", false)
const logs_data = new Array() const logs_data = new Array()
const logs_folder = fs.readdirSync(__glob.LOGS) const logs_folder = fs.readdirSync(__glob.LOGS)
for(var log of logs_folder) { for(var log of logs_folder) {
@@ -371,53 +474,94 @@ function init() {
IOAnswer("/ADMIN/LOGS", logs_data) IOAnswer("/ADMIN/LOGS", logs_data)
}) })
// CHECKED : 24/04/2025
IORequest("/ADMIN/MAINTENANCE/RESTART", (reason) => { IORequest("/ADMIN/MAINTENANCE/RESTART", (reason) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false)
if(!reason) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false) if(!reason) return IOAnswer("/ADMIN/MAINTENANCE/RESTART", false)
restart(reason) restart(reason)
}) })
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/SWITCH_ADMIN", (userId) => { IORequest("/ADMIN/USERS/SWITCH_ADMIN", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", false)
users.setAdmin(userId) users.setAdmin(userId)
IOAnswer("/ADMIN/USERS/PROMOTE_ADMIN", true) IOAnswer("/ADMIN/USERS/SWITCH_ADMIN", true)
}) })
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/FULL_BAN", (userId) => { IORequest("/ADMIN/USERS/FULL_BAN", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/FULL_BAN", false)
users.setFullBan(userId) users.setFullBan(userId)
IOAnswer("/ADMIN/USERS/FULL_BAN", true) IOAnswer("/ADMIN/USERS/FULL_BAN", true)
}) })
// CHECKED : 24/04/2025
IORequest("/ADMIN/USERS/DELETE", (userId) => { IORequest("/ADMIN/USERS/DELETE", (userId) => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(socketUser.identity.id == userId) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(!users.getUserById(userId)) return IOAnswer("/ADMIN/USERS/DELETE", false)
if(users.getUserById(userId).isAdmin()) return IOAnswer("/ADMIN/USERS/DELETE", false)
users.removeUser(userId) users.removeUser(userId)
const userSocket = UsersBySocket.get(userId)
if(userSocket) {
const socket = io.sockets.sockets.get(userSocket)
if(socket) {
socket.emit("DELETED")
socket.disconnect()
}
}
IOAnswer("/ADMIN/USERS/DELETE", true) IOAnswer("/ADMIN/USERS/DELETE", true)
}) })
IORequest("/ADMIN/PLAYER/GETALLSTATE", () => { // CHECKED : 24/04/2025
IORequest("/ADMIN/PLAYER/GETALLSTATE", async () => {
if(!socketUser.isAdmin()) return IOAnswer("/ADMIN/PLAYER/GETTALLSTATE", false)
const allPlayers = players.getAllPlayers() const allPlayers = players.getAllPlayers()
const states = new Array() const states = new Array()
for(var player of allPlayers) { for(var player in allPlayers) {
states.push(player.getState()) await states.push(await player.getState())
} }
IOAnswer("/ADMIN/PLAYER/GETALLSTATE", states) IOAnswer("/ADMIN/PLAYER/GETALLSTATE", states)
}) })
} }
IORequest("/OWNER/USERS/SWITCH_MOD", (userId, guildId) => { // CHECKED : 24/04/2025
IORequest("/OWNER/USERS/SWITCH_MOD", (data) => {
if(!data["userId"] || !data["guildId"]) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
const userId = data["userId"]
const guildId = data["guildId"]
if(socketUser.identity.id == userId) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
if(!socketUser.isOwner(guildId)) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false) if(!socketUser.isOwner(guildId)) return IOAnswer("/OWNER/USERS/SWITCH_MOD", false)
users.setGuildMod(userId, guildId) users.setGuildMod(userId, guildId)
IOAnswer("/OWNER/USERS/SWITCH_MOD", true) IOAnswer("/OWNER/USERS/SWITCH_MOD", true)
}) })
IORequest("/MOD/USERS/BAN", (userId, guildId) => {
// CHECKED : 24/04/2025
IORequest("/MOD/USERS/BAN", (data) => {
if(!data["userId"] || !data["guildId"]) return IOAnswer("/MOD/USERS/BAN", false)
const userId = data["userId"]
const guildId = data["guildId"]
if(socketUser.identity.id == userId) return IOAnswer("/MOD/USERS/BAN", false)
if(!socketUser.isMod(guildId)) return IOAnswer("/MOD/USERS/BAN", false) if(!socketUser.isMod(guildId)) return IOAnswer("/MOD/USERS/BAN", false)
users.setGuildBan(userId, guildId) users.setGuildBan(userId, guildId)
IOAnswer("/OWNER/USERS/BAN", true) IOAnswer("/MOD/USERS/BAN", true)
}) })
// UTILS // UTILS
IORequest("/REPORT", (level, desc) => { // CHECKED : 24/04/2025
const report = new Report(socketUser.identity.username, level, desc).send() IORequest("/REPORT", (data) => {
if(data.length < 2) return IOAnswer("/REPORT", false)
if(!data["level"] || !data["desc"]) return IOAnswer("/REPORT", false)
const report = new Report(socketUser.identity.username, data["level"], data["desc"]).send()
IOAnswer("/REPORT", true) IOAnswer("/REPORT", true)
}) })
@@ -457,12 +601,16 @@ function init() {
function checkUserGuild(socketUser, guildId) { function checkUserGuild(socketUser, guildId) {
// Vérifie si l'utilisateur n'est pas banni de la guilde // Check if the guildId is referenced in the bot guilds
if(!discordBot.getGuilds().has(guildId)) {
wlog.warn("La guilde : " + guildId + " n'est pas référencée dans le bot")
return false
}
if(socketUser.isBanned(guildId)) { if(socketUser.isBanned(guildId)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est banni de la guilde : " + guildId) wlog.warn("L'utilisateur '" + socketUser.identity.username + "' est banni de la guilde : " + guildId)
return false return false
} }
if(!socketUser.guilds.includes(guildId)) { if(!socketUser.guilds.find(g => g.id == guildId)) {
wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas membre de la guilde : " + guildId) wlog.warn("L'utilisateur '" + socketUser.identity.username + "' n'est pas membre de la guilde : " + guildId)
// Si user admin, override // Si user admin, override
if(!socketUser.isAdmin()) { if(!socketUser.isAdmin()) {
@@ -470,6 +618,7 @@ function init() {
} }
wlog.log("L'utilisateur '" + socketUser.identity.username + "' est admin donc à le droit d'accéder à la guilde : " + guildId) wlog.log("L'utilisateur '" + socketUser.identity.username + "' est admin donc à le droit d'accéder à la guilde : " + guildId)
} }
return true return true
} }
@@ -492,13 +641,19 @@ function init() {
} }
socket.on("disconnect", () => {
function handleDisconnect() {
if(socketUser) {
wlog.log("Déconnexion de l'utilisateur : " + socketUser.identity.username + " (" + socketUser.identity.id + ") - Socket : " + socket.id)
allConnectedUsers.splice(allConnectedUsers.indexOf(socketUser.identity), 1) allConnectedUsers.splice(allConnectedUsers.indexOf(socketUser.identity), 1)
socket.leave("admin")
removeGuildConnectedUser(socketUser.identity) removeGuildConnectedUser(socketUser.identity)
process.emit("USERS_UPDATE") process.emit("USERS_UPDATE")
clog.log(`Déconnexion du client : ${socket.id}`) if(socketUser.isAdmin()) {
}) socket.leave("ADMIN")
}
UsersBySocket.delete(socketUser.identity.id)
}
}
function sendSession() { function sendSession() {
const newSession = session.addSession(socket.id) const newSession = session.addSession(socket.id)
@@ -509,17 +664,16 @@ function init() {
function IORequest(RequestName, RequestCallback) { function IORequest(RequestName, RequestCallback) {
socket.on(GQname, (value) => { socket.on(RequestName, (value) => {
wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - POST/" + GQname + " - [RECIEVED]") wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + RequestName + " - [RECIEVED]")
GQcallback(value) RequestCallback(value)
}) })
} }
function IOAnswer(AnswerName, AnswerValue) { function IOAnswer(AnswerName, AnswerValue) {
wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - POST/" + GRname + " - [ANSWERED]") wlog.log(socketUser.identity.username + " - Socket : " + socket.id + " - " + AnswerName + " - [ANSWERED]")
socket.emit("ANSWER/" + GRname, GRvalue) socket.emit(AnswerName, AnswerValue)
process.emit("PLAYERS_UPDATE")
} }
}) })
@@ -531,16 +685,16 @@ function init() {
function AdminRequest(GRname, GRvalue) { function AdminRequest(GRname, GRvalue) {
io.to("admin").emit("ALWAYS/" + GRname, GRvalue) io.to("ADMIN").emit("ALWAYS/" + GRname, GRvalue)
} }
function addGuildConnectedUser(user, guilds) { function addGuildConnectedUser(user, guilds) {
for(var guild of guilds) { for(var guild of guilds) {
if(!guildConnectedUsers.has(guild)) { if(!guildConnectedUsers.has(guild)) {
guildConnectedUsers.set(guild, new Array()) guildConnectedUsers.set(guild.id, new Array())
} }
guildConnectedUsers.get(guild).push(user) guildConnectedUsers.get(guild.id).push(user)
} }
} }

View File

@@ -1,10 +1,12 @@
const { LogType } = require('loguix'); const { LogType } = require('loguix');
const dlog = new LogType("DiscordAuth"); const dlog = new LogType("DiscordAuth");
const { getPort, getToken, getWebsiteLink, getClientSecret } = require('../../utils/Database/Configuration'); const { getWebsiteLink, getClientSecret } = require('../../utils/Database/Configuration');
const discordBot = require("../../discord/Bot")
async function getDiscordUser(sessionId, auth_code) { async function getDiscordUser(sessionId, auth_code) {
return new Promise((resolve, reject) => {
const discordBot = require("../../discord/Bot")
const discordBotClient = discordBot.getClient() const discordBotClient = discordBot.getClient()
dlog.step.init("discord_auth_" + sessionId, "Authentification Discord de la session :" + sessionId); dlog.step.init("discord_auth_" + sessionId, "Authentification Discord de la session :" + sessionId);
@@ -25,6 +27,13 @@ async function getDiscordUser(sessionId, auth_code) {
}, },
body: params, body: params,
}).then(accessTokenResp => accessTokenResp.json()).then(accessToken => { }).then(accessTokenResp => accessTokenResp.json()).then(accessToken => {
if (accessToken.error) {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération du token d'accès Discord associé à la session : " + sessionId + " : " + accessToken.error + " : " + accessToken.error_description);
resolve("ACCESS_TOKEN_ERROR");
return;
}
dlog.log("Récupération réussi du token d'accès Discord associé à la session : " + sessionId); dlog.log("Récupération réussi du token d'accès Discord associé à la session : " + sessionId);
fetch("https://discord.com/api/users/@me", { fetch("https://discord.com/api/users/@me", {
@@ -46,22 +55,91 @@ async function getDiscordUser(sessionId, auth_code) {
identity: user, identity: user,
guilds: guilds, guilds: guilds,
} }
return userData; resolve(userData);
}).catch(err => { }).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des guildes de l'utilisateur Discord" + " avec le nom d'utilisateur : " + user.username + " (" + user.id + ")" + " associé à la session : " + sessionId + " : " + err); dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des guildes de l'utilisateur Discord" + " avec le nom d'utilisateur : " + user.username + " (" + user.id + ")" + " associé à la session : " + sessionId + " : " + err);
return "GUILDS_ERROR"; resolve("GUILDS_ERROR");
}); });
}).catch(err => { }).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId + " : " + err); dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération des informations de l'utilisateur Discord associé à la session : " + sessionId + " : " + err);
return "USER_INFO_ERROR"; resolve( "USER_INFO_ERROR");
}) })
}).catch(err => { }).catch(err => {
dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération du token d'accès Discord associé à la session : " + sessionId + " : " + err); dlog.step.error("discord_auth_" + sessionId, "Erreur lors de la récupération du token d'accès Discord associé à la session : " + sessionId + " : " + err);
return "ACCESS_TOKEN_ERROR"; resolve("ACCESS_TOKEN_ERROR");
})
}) })
} }
module.exports = {getDiscordUser} function refreshToken(refresh_token) {
return new Promise((resolve, reject) => {
const discordBot = require("../../discord/Bot")
const params = new URLSearchParams();
params.append("client_id", discordBot.getClient().user.id);
params.append("client_secret", getClientSecret());
params.append("grant_type", "refresh_token");
params.append("refresh_token", refresh_token);
params.append("scope", "identify guilds");
fetch("https://discord.com/api/oauth2/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
}).then(accessTokenResp => accessTokenResp.json()).then(accessToken => {
if (accessToken.error) {
dlog.error("Erreur lors de la récupération du token d'accès Discord : " + accessToken.error + " : " + accessToken.error_description);
resolve(null);
return;
}
resolve(accessToken);
}).catch(err => {
dlog.error("Erreur lors de la récupération du token d'accès Discord : " + err);
resolve(null);
})
})
}
function getUserGuilds(accessToken) {
return new Promise((resolve, reject) => {
fetch("https://discord.com/api/users/@me/guilds", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(guildsResp => guildsResp.json()).then(guilds => {
if (guilds.error) {
dlog.error("Erreur lors de la récupération des guildes de l'utilisateur Discord : " + guilds.error + " : " + guilds.error_description);
resolve(null);
return;
}
resolve(guilds);
}).catch(err => {
dlog.error( "Erreur lors de la récupération des guildes de l'utilisateur Discord : " + err);
resolve(null);
})
})
}
function getUserIdentity(accessToken) {
return new Promise((resolve, reject) => {
fetch("https://discord.com/api/users/@me", {
headers: {
authorization: `${accessToken.token_type} ${accessToken.access_token}`,
},
}).then(userResp => userResp.json()).then(user => {
if (user.error) {
dlog.error("Erreur lors de la récupération des informations de l'utilisateur Discord : " + user.error + " : " + user.error_description);
resolve(null);
return;
}
resolve(user);
}).catch(err => {
dlog.error("Erreur lors de la récupération des informations de l'utilisateur Discord : " + err);
resolve(null);
})
})
}
module.exports = {getDiscordUser, refreshToken, getUserGuilds, getUserIdentity}

View File

@@ -3,11 +3,11 @@ const { __glob } = require('../../utils/GlobalVars');
const { generateToken } = require('../../utils/TokenManager'); const { generateToken } = require('../../utils/TokenManager');
const { LogType } = require('loguix'); const { LogType } = require('loguix');
const clog = new LogType("User"); const clog = new LogType("User");
const discordAuth = require('./DiscordAuth');
const e = require('cors');
const UserDB = new Database("Users", __glob.USERFILE, []); const UserDB = new Database("Users", __glob.USERFILE, []);
const userList = new Array(); var userList = new Array();
loadUsers();
class User { class User {
auth; auth;
identity; identity;
@@ -23,38 +23,60 @@ class User {
} }
setAdmin() { setAdmin() {
if (this.labels.includes("ADMIN")) { const userInUserList = userList.find(user => user.identity.id === this.identity.id);
this.labels.splice(this.labels.indexOf("ADMIN"), 1); if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
if (userInUserList.labels.includes("ADMIN")) {
userInUserList.labels.splice(userInUserList.labels.indexOf("ADMIN"), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus admin.`); clog.log(`L'utilisateur ${this.identity.username} n'est plus admin.`);
} else { } else {
this.labels.push("ADMIN"); userInUserList.labels.push("ADMIN");
clog.log(`L'utilisateur ${this.identity.username} est maintenant admin.`); clog.log(`L'utilisateur ${this.identity.username} est maintenant admin.`);
} }
saveUsers()
} }
setBan(guildId) { setBan(guildId) {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
const banLabel = `BAN_${guildId}`; const banLabel = `BAN_${guildId}`;
if (this.labels.includes(banLabel)) { if (userInUserList.labels.includes(banLabel)) {
this.labels.splice(this.labels.indexOf(banLabel), 1); userInUserList.labels.splice(userInUserList.labels.indexOf(banLabel), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus banni du serveur ${guildId}.`); clog.log(`L'utilisateur ${this.identity.username} n'est plus banni du serveur ${guildId}.`);
} else { } else {
this.labels.push(banLabel); userInUserList.labels.push(banLabel);
clog.log(`L'utilisateur ${this.identity.username} est maintenant banni du serveur ${guildId}.`); clog.log(`L'utilisateur ${this.identity.username} est maintenant banni du serveur ${guildId}.`);
} }
saveUsers()
} }
createToken() { createToken() {
const token = generateToken(); const token = generateToken(this.identity.id);
this.tokens.push(token); const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.tokens.push(token);
saveUsers(); saveUsers();
clog.log(`Token créé pour l'utilisateur ${this.identity.username}.`); clog.log(`Token créé pour l'utilisateur ${this.identity.username}.`);
return token; return token;
} }
removeToken(token) { removeToken(token) {
const index = this.tokens.indexOf(token); const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
const index = userInUserList.tokens.indexOf(token);
if (index > -1) { if (index > -1) {
this.tokens.splice(index, 1); userInUserList.tokens.splice(index, 1);
saveUsers(); saveUsers();
clog.log(`Token supprimé pour l'utilisateur ${this.identity.username}.`); clog.log(`Token supprimé pour l'utilisateur ${this.identity.username}.`);
} else { } else {
@@ -62,6 +84,58 @@ class User {
} }
} }
clearToken() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.tokens = [];
saveUsers();
clog.log(`Tous les tokens supprimés pour l'utilisateur ${this.identity.username}.`);
return userInUserList.tokens;
}
clearAuth() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.auth = null;
saveUsers();
clog.log(`Authentification supprimée pour l'utilisateur ${this.identity.username}.`);
}
destroyAuth() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
userInUserList.auth = null;
userInUserList.tokens = [];
saveUsers();
clog.log(`Authentification et tokens supprimés pour l'utilisateur ${this.identity.username}.`);
}
setFullBan() {
const userInUserList = userList.find(user => user.identity.id === this.identity.id);
if (!userInUserList) {
clog.warn(`Utilisateur ${this.identity.username} non trouvé dans la liste des utilisateurs.`);
return null;
}
if (userInUserList.labels.find(label => label == "BAN")) {
userInUserList.labels.splice(userInUserList.labels.indexOf("BAN"), 1);
clog.log(`L'utilisateur ${this.identity.username} n'est plus banni.`);
} else {
userInUserList.labels.push("BAN");
clog.log(`L'utilisateur ${this.identity.username} est maintenant banni.`);
}
saveUsers()
}
isBanned(guildId) { isBanned(guildId) {
const banLabel = `BAN_${guildId}`; const banLabel = `BAN_${guildId}`;
return this.labels.includes(banLabel); return this.labels.includes(banLabel);
@@ -80,15 +154,142 @@ class User {
isOwner(guildId) { isOwner(guildId) {
const ownerLabel = `OWNER_${guildId}`; const ownerLabel = `OWNER_${guildId}`;
if(this.isAdmin()) return true;
return this.labels.includes(ownerLabel); return this.labels.includes(ownerLabel);
} }
} }
// ADD //REFRESH USER
function addUser(auth, identity, guilds) { async function refreshAllUserInformation() {
await loadUsers();
clog.log("Récupération des informations de tous les utilisateurs...");
for (const user of userList) {
await refreshUserInformation(user.identity.id);
}
saveUsers();
}
async function refreshUserInformation(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Récupération (Refresh) des informations de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const refresh_token = user.auth.refresh_token;
const authCredientials = await discordAuth.refreshToken(refresh_token);
if(authCredientials) {
user.auth = authCredientials;
const guilds = await discordAuth.getUserGuilds(authCredientials);
const identity = await discordAuth.getUserIdentity(authCredientials);
if(identity) {
user.identity = identity;
clog.log(`Récupération réussie des informations de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la récupération des informations de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
if(guilds) {
user.guilds = guilds;
clog.log(`Récupération réussie des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la récupération des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.guilds = user.guilds;
}
} else {
clog.warn(`Erreur lors de la récupération du token d'accès pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
// Delete tokens to oblige the user to reauthenticate
// Clear auth
user.destroyAuth();
return null;
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
}
async function updateGuilds(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const guilds = await discordAuth.getUserGuilds(user.auth);
if(guilds) {
user.guilds = guilds;
clog.log(`Mise à jour réussie des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour des guildes de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.guilds = user.guilds;
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
saveUsers();
return user.guilds;
}
async function updateIdentity(id) {
const user = getUserById(id);
if (!user) {
clog.warn(`Utilisateur ${id} non trouvé.`);
return null;
}
clog.log(`Mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})...`);
if (user.auth) {
const identity = await discordAuth.getUserIdentity(user.auth);
if(identity) {
user.identity = identity;
clog.log(`Mise à jour réussie de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
else {
clog.warn(`Erreur lors de la mise à jour de l'identité de l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
// Update the user in the list
const userInUserList = userList.find(u => u.identity.id === user.identity.id);
if (userInUserList) {
userInUserList.auth = user.auth;
userInUserList.identity = user.identity;
}
} else {
clog.warn(`Aucune authentification trouvée pour l'utilisateur ${user.identity.username} (${user.identity.id})`);
}
saveUsers();
return user.identity;
}
// EDIT USER
/**
*
* @param {*} auth
* @param {*} identity
* @param {*} guilds
* @returns {User} user
*/
async function addUser(auth, identity, guilds) {
// Check if the user already exists // Check if the user already exists
const existingUser = userList.find(user => user.identity.id === identity.id); const existingUser = userList.find(user => user.identity.id === identity.id);
if (existingUser) { if (existingUser) {
@@ -107,7 +308,7 @@ function addUser(auth, identity, guilds) {
const newUser = new User(auth, identity, [], [], guilds); const newUser = new User(auth, identity, [], [], guilds);
userList.push(newUser); userList.push(newUser);
saveUsers(); await saveUsers();
return newUser; return newUser;
} }
@@ -233,6 +434,10 @@ function setGuildMod(id, guildId) {
function setGuildBan(id, guildId) { function setGuildBan(id, guildId) {
const user = getUserById(id); const user = getUserById(id);
if (user) { if (user) {
if(user.isAdmin()) {
clog.warn(`L'utilisateur ${user.identity.username} est admin, il ne peut pas être banni.`);
return;
}
user.setBan(guildId); user.setBan(guildId);
saveUsers(); saveUsers();
} else { } else {
@@ -243,21 +448,28 @@ function setGuildBan(id, guildId) {
function setFullBan(id) { function setFullBan(id) {
const user = getUserById(id); const user = getUserById(id);
if (user) { if (user) {
user.labels.push("BAN"); if(user.isAdmin()) {
clog.warn(`L'utilisateur ${user.identity.username} est admin, il ne peut pas être banni.`);
return;
}
user.setFullBan();
saveUsers(); saveUsers();
} else { } else {
clog.warn(`Utilisateur ${id} non trouvé.`); clog.warn(`Utilisateur ${id} non trouvé.`);
} }
} }
function setGuildOwner(id, guildId) { function setGuildOwner(id, guildId, force) {
const user = getUserById(id); const user = getUserById(id);
if (user) { if (user) {
const ownerLabel = `OWNER_${guildId}`; const ownerLabel = `OWNER_${guildId}`;
if (user.labels.includes(ownerLabel)) { if (user.labels.includes(ownerLabel) && !force) {
user.labels.splice(user.labels.indexOf(ownerLabel), 1); user.labels.splice(user.labels.indexOf(ownerLabel), 1);
clog.log(`L'utilisateur ${user.identity.username} n'est plus propriétaire du serveur ${guildId}.`); clog.log(`L'utilisateur ${user.identity.username} n'est plus propriétaire du serveur ${guildId}.`);
} else { } else {
if(force && user.labels.includes(ownerLabel)) {
return;
}
user.labels.push(ownerLabel); user.labels.push(ownerLabel);
clog.log(`L'utilisateur ${user.identity.username} est maintenant propriétaire du serveur ${guildId}.`); clog.log(`L'utilisateur ${user.identity.username} est maintenant propriétaire du serveur ${guildId}.`);
} }
@@ -272,8 +484,8 @@ function setGuildOwner(id, guildId) {
function loadUsers() { function loadUsers() {
UserDB.load() UserDB.load()
userList.length = 0; userList = new Array();
for (const user in UserDB.data) { for (const user of UserDB.getData()) {
userList.push(new User(user.auth, user.identity, user.tokens, user.labels, user.guilds)); userList.push(new User(user.auth, user.identity, user.tokens, user.labels, user.guilds));
} }
clog.log(`Chargement de ${userList.length} utilisateurs.`); clog.log(`Chargement de ${userList.length} utilisateurs.`);
@@ -298,4 +510,23 @@ function saveUsers() {
module.exports = {User} module.exports = {User}
module.exports = {addUser, setGuildOwner , setFullBan, removeUser, getUserByToken , getUserById, getUsers, setAdmin, setGuildMod, setGuildBan, addToken, removeToken, getSimpleUsers, getSimpleUser} module.exports = {
addUser,
setGuildOwner,
setFullBan,
removeUser,
getUserByToken,
getUserById,
getUsers,
setAdmin,
setGuildMod,
setGuildBan,
addToken,
removeToken,
getSimpleUsers,
getSimpleUser,
refreshUserInformation,
refreshAllUserInformation,
updateGuilds,
updateIdentity
};

View File

@@ -83,6 +83,10 @@ class Database {
} }
getData() {
return this.data
}
} }

View File

@@ -1,2 +0,0 @@
- Setup serveur
-