Réécriture complète 4.0
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6m16s

This commit is contained in:
2025-06-09 16:29:12 +02:00
parent f2c6388da6
commit ddd617317c
133 changed files with 8092 additions and 4332 deletions

View File

@@ -0,0 +1,11 @@
import * as lcd_status from "./lcd_status"
import * as refresh_status from "./refresh_status"
import * as test_connection from "./test_connection"
import type { Button } from "@/types"
export default [
lcd_status,
refresh_status,
test_connection
] as Button[]

View File

@@ -0,0 +1,88 @@
import { EmbedBuilder, MessageFlags } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import crypto from "crypto"
import * as Freebox from "@/utils/freebox"
import type { APIResponseData, APIResponseDataError, GetChallenge, LcdConfig, OpenSession } from "@/types/freebox"
import type { GuildFbx } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "freebox_lcd_status"
export async function execute(interaction: ButtonInteraction) {
await interaction.deferReply({ flags: MessageFlags.Ephemeral })
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.followUp({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildFbx") as GuildFbx
if (!dbData.enabled || !dbData.host || !dbData.appToken) {
return interaction.followUp({ content: t(interaction.locale, "freebox.general.incomplete_configuration"), flags: MessageFlags.Ephemeral })
}
try {
// Connexion à l'API Freebox
const challengeData = await Freebox.Login.Challenge(dbData.host) as APIResponseData<GetChallenge>
if (!challengeData.success) return await Freebox.handleError(challengeData as APIResponseDataError, interaction, false)
const password = crypto.createHmac("sha1", dbData.appToken).update(challengeData.result.challenge).digest("hex")
const sessionData = await Freebox.Login.Session(dbData.host, password) as APIResponseData<OpenSession>
if (!sessionData.success) return await Freebox.handleError(sessionData as APIResponseDataError, interaction, false)
const sessionToken = sessionData.result.session_token
if (!sessionToken) return await interaction.followUp({ content: t(interaction.locale, "freebox.auth.session_token_failed"), flags: MessageFlags.Ephemeral })
// Récupération de la configuration LCD
const lcdData = await Freebox.Get.LcdConfig(dbData.host, sessionToken) as APIResponseData<LcdConfig>
if (!lcdData.success) return await Freebox.handleError(lcdData as APIResponseDataError, interaction, false)
const lcdConfig = lcdData.result
// Création de l'embed avec les informations LCD
const embed = new EmbedBuilder()
.setTitle(t(interaction.locale, "freebox.lcd.config_title"))
.setColor(lcdConfig.led_strip_enabled ? 0x00ff00 : 0xff0000)
.addFields(
{
name: t(interaction.locale, "freebox.lcd.led_strip"),
value: lcdConfig.led_strip_enabled ? t(interaction.locale, "freebox.lcd.led_strip_on") : t(interaction.locale, "freebox.lcd.led_strip_off"),
inline: true
},
{
name: t(interaction.locale, "freebox.lcd.brightness"),
value: `${lcdConfig.brightness}%`,
inline: true
},
{
name: t(interaction.locale, "freebox.lcd.orientation"),
value: lcdConfig.orientation === 0 ? t(interaction.locale, "freebox.lcd.orientation_portrait") : t(interaction.locale, "freebox.lcd.orientation_landscape"),
inline: true
}
)
// Informations du timer si configuré
if (dbData.lcd) {
const timerStatus = dbData.lcd.enabled ? t(interaction.locale, "freebox.status.timer_enabled") : t(interaction.locale, "freebox.status.timer_disabled")
const botManaged = dbData.lcd.botId ? `<@${dbData.lcd.botId}>` : t(interaction.locale, "freebox.status.timer_no_manager")
const morningTime = dbData.lcd.morningTime ?? t(interaction.locale, "freebox.status.timer_not_configured")
const nightTime = dbData.lcd.nightTime ?? t(interaction.locale, "freebox.status.timer_not_configured")
embed.addFields({
name: t(interaction.locale, "freebox.lcd.timer_auto"),
value: [
t(interaction.locale, "freebox.timer.status_field", { status: timerStatus }),
t(interaction.locale, "freebox.timer.managed_by", { manager: botManaged }),
t(interaction.locale, "freebox.timer.morning", { time: morningTime }),
t(interaction.locale, "freebox.timer.night", { time: nightTime })
].join('\n'),
inline: false
})
}
embed.setTimestamp()
return await interaction.followUp({ embeds: [embed], flags: MessageFlags.Ephemeral })
} catch (error) {
console.error("Erreur lors de la récupération de l'état LCD:", error)
return interaction.followUp({ content: t(interaction.locale, "freebox.lcd.unexpected_error"), flags: MessageFlags.Ephemeral })
}
}

View File

@@ -0,0 +1,76 @@
import { EmbedBuilder, MessageFlags, ButtonBuilder, ButtonStyle, ActionRowBuilder } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import type { GuildFbx } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "freebox_refresh_status"
export async function execute(interaction: ButtonInteraction) {
await interaction.deferUpdate()
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.followUp({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildFbx") as GuildFbx
// Reconstruire l'embed de statut actualisé
const embed = new EmbedBuilder()
.setTitle(t(interaction.locale, "freebox.status.title"))
.setColor(dbData.enabled ? 0x00ff00 : 0xff0000)
.addFields(
{
name: t(interaction.locale, "freebox.status.config_section"),
value: [
t(interaction.locale, "freebox.status.module_field", { status: dbData.enabled ? t(interaction.locale, "freebox.common.enabled") : t(interaction.locale, "freebox.common.disabled") }),
t(interaction.locale, "freebox.status.host_field", { value: dbData.host ? `\`${dbData.host}\`` : t(interaction.locale, "freebox.status.host_not_configured") }),
t(interaction.locale, "freebox.status.token_field", { status: dbData.appToken ? t(interaction.locale, "freebox.status.token_configured") : t(interaction.locale, "freebox.status.token_not_configured") })
].join('\n'),
inline: false
}
)
// Informations LCD si disponibles
if (dbData.lcd) {
const lcdStatus = dbData.lcd.enabled ? t(interaction.locale, "freebox.common.enabled") : t(interaction.locale, "freebox.common.disabled")
const botManaged = dbData.lcd.botId ? `<@${dbData.lcd.botId}>` : t(interaction.locale, "freebox.status.timer_no_manager")
const morningTime = dbData.lcd.morningTime ?? t(interaction.locale, "freebox.status.timer_not_configured")
const nightTime = dbData.lcd.nightTime ?? t(interaction.locale, "freebox.status.timer_not_configured")
embed.addFields({
name: t(interaction.locale, "freebox.status.timer_section"),
value: [
t(interaction.locale, "freebox.timer.status_field", { status: lcdStatus }),
t(interaction.locale, "freebox.timer.managed_by", { manager: botManaged }),
t(interaction.locale, "freebox.timer.morning", { time: morningTime }),
t(interaction.locale, "freebox.timer.night", { time: nightTime })
].join('\n'),
inline: false
})
}
embed.setTimestamp()
// Reconstruire les boutons
const buttons = new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setCustomId("freebox_test_connection")
.setLabel(t(interaction.locale, "freebox.buttons.test_connection"))
.setEmoji("🔌")
.setStyle(ButtonStyle.Primary)
.setDisabled(!dbData.appToken),
new ButtonBuilder()
.setCustomId("freebox_lcd_status")
.setLabel(t(interaction.locale, "freebox.buttons.lcd_status"))
.setEmoji("💡")
.setStyle(ButtonStyle.Secondary)
.setDisabled(!dbData.appToken),
new ButtonBuilder()
.setCustomId("freebox_refresh_status")
.setLabel(t(interaction.locale, "freebox.buttons.refresh_status"))
.setEmoji("🔄")
.setStyle(ButtonStyle.Success)
)
return interaction.editReply({ embeds: [embed], components: [buttons] })
}

View File

@@ -0,0 +1,71 @@
import { EmbedBuilder, MessageFlags } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import crypto from "crypto"
import * as Freebox from "@/utils/freebox"
import type { APIResponseData, APIResponseDataError, APIResponseDataVersion, ConnectionStatus, GetChallenge, OpenSession } from "@/types/freebox"
import type { GuildFbx } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "freebox_test_connection"
export async function execute(interaction: ButtonInteraction) {
await interaction.deferReply({ flags: MessageFlags.Ephemeral })
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.followUp({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildFbx") as GuildFbx
if (!dbData.enabled || !dbData.host || !dbData.appToken) {
return interaction.followUp({ content: t(interaction.locale, "freebox.general.incomplete_configuration"), flags: MessageFlags.Ephemeral })
}
try {
// Test de la version API
const versionData = await Freebox.Core.Version(dbData.host) as APIResponseDataVersion
// Test d'authentification
const challengeData = await Freebox.Login.Challenge(dbData.host) as APIResponseData<GetChallenge>
if (!challengeData.success) return await Freebox.handleError(challengeData as APIResponseDataError, interaction, false)
const password = crypto.createHmac("sha1", dbData.appToken).update(challengeData.result.challenge).digest("hex")
const sessionData = await Freebox.Login.Session(dbData.host, password) as APIResponseData<OpenSession>
if (!sessionData.success) return await Freebox.handleError(sessionData as APIResponseDataError, interaction, false)
const sessionToken = sessionData.result.session_token
if (!sessionToken) return await interaction.followUp({ content: t(interaction.locale, "freebox.auth.session_token_failed"), flags: MessageFlags.Ephemeral })
// Test de la connexion
const connectionData = await Freebox.Get.Connection(dbData.host, sessionToken) as APIResponseData<ConnectionStatus>
if (!connectionData.success) return await Freebox.handleError(connectionData as APIResponseDataError, interaction, false)
// Création de l'embed de succès
const embed = new EmbedBuilder()
.setTitle(t(interaction.locale, "freebox.test.connection_success_title"))
.setColor(0x00ff00)
.addFields(
{
name: t(interaction.locale, "freebox.test.api_field"),
value: t(interaction.locale, "freebox.test.api_version", { version: versionData.api_version }),
inline: true
},
{
name: t(interaction.locale, "freebox.test.auth_field"),
value: t(interaction.locale, "freebox.test.token_valid"),
inline: true
},
{
name: t(interaction.locale, "freebox.test.connection_field"),
value: connectionData.result.state === "up" ?
t(interaction.locale, "freebox.test.connection_active") :
t(interaction.locale, "freebox.test.connection_inactive"),
inline: true
}
)
.setTimestamp()
return await interaction.followUp({ embeds: [embed], flags: MessageFlags.Ephemeral })
} catch (error) {
console.error("Erreur lors du test de connexion Freebox:", error)
return interaction.followUp({ content: t(interaction.locale, "freebox.test.connection_error"), flags: MessageFlags.Ephemeral })
}
}