diff --git a/.env.example b/.env.example index 36cd4eb..7f886eb 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,3 @@ -# Configuration Discord Bot -TOKEN=votre_token_discord -STATUS=online -INTERVAL=3600 - # Configuration Zabbix (optionnel) ENABLE_ZABBIX=false ZABBIX_SERVER=zabbix-server.example.com diff --git a/Dockerfile b/Dockerfile index b72b160..743b41c 100755 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,12 @@ FROM debian:trixie-slim WORKDIR /app ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=fr_FR.UTF-8 +ENV LC_ALL=fr_FR.UTF-8 RUN apt-get update && apt-get install -y --no-install-recommends \ apt-utils \ + locales \ python3 \ python3-pip \ python3-venv \ @@ -14,16 +17,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && dpkg -i zabbix-release_latest_7.4+debian12_all.deb \ && apt-get update \ && apt-get install -y --no-install-recommends zabbix-agent2 \ + && sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen \ + && locale-gen \ && rm -rf /var/lib/apt/lists/* \ && rm zabbix-release_latest_7.4+debian12_all.deb COPY requirements.txt . -COPY bot.py . -COPY statuts.txt . +COPY run-web.py . +COPY ./webapp ./webapp +COPY ./discordbot ./discordbot +COPY ./database ./database COPY zabbix_agent2.conf /etc/zabbix/zabbix_agent2.conf COPY start.sh /start.sh -RUN pip3 install --no-cache-dir --break-system-packages --root-user-action=ignore -r requirements.txt && \ +RUN python3 -m venv /app/venv && \ + /app/venv/bin/pip install --no-cache-dir -r requirements.txt && \ chmod +x /start.sh CMD ["/start.sh"] \ No newline at end of file diff --git a/README.md b/README.md index 68e01d3..e2d09af 100755 --- a/README.md +++ b/README.md @@ -1,175 +1,188 @@ +# MamieHenriette 👵 -# 👵 Mamie Henriette - Discord Status Bot 🤖 +**Bot multi-plateformes pour Discord, Twitch et YouTube Live** -## 📖 Description -Mamie Henriette est un bot Discord intelligent qui change automatiquement de statut, surveillant et gérant votre serveur avec une touche d'humour et de caractère. +## Vue d'ensemble -## ✨ Fonctionnalités +Mamie Henriette est un bot intelligent open-source développé spécifiquement pour les communautés de [STEvE](https://www.youtube.com/@STEvE_YT) sur YouTube, [Twitch](https://www.twitch.tv/steve_yt) et Discord. -- Changement cyclique automatique des statuts -- Configuration flexible via variables d'environnement -- Gestion des erreurs et logging -- Support multi-statuts Discord -- Déploiement simplifié avec Docker -- 📊 Surveillance optionnelle avec Zabbix +> ⚠️ **Statut** : En cours de développement -## 🛠 Prérequis +### Caractéristiques principales -- Docker et Docker Compose -- Compte Discord et Token du bot -- (Optionnel) Serveur Zabbix pour la surveillance +- Interface web d'administration complète +- Gestion multi-plateformes (Discord, Twitch, YouTube Live) +- Système de notifications automatiques +- Base de données intégrée pour la persistance +- Surveillance optionnelle avec Zabbix *(non testée)* -## 📦 Installation +## Fonctionnalités + +### Discord +- **Statuts dynamiques** : Rotation automatique des humeurs (10 min) +- **Notifications Humble Bundle** : Surveillance et alertes automatiques (30 min) +- **Commandes personnalisées** : Gestion via interface web +- **Modération** : Outils intégrés + +### Twitch *(en développement)* +- **Chat bot** : Commandes et interactions +- **Événements live** : Notifications de stream + +### YouTube Live *(en développement)* +- **Chat bot** : Modération et commandes +- **Événements** : Notifications de diffusion + +### Interface d'administration +- **Dashboard** : Vue d'ensemble et statistiques +- **Configuration** : Tokens, paramètres des plateformes +- **Gestion des humeurs** : Création et modification des statuts +- **Commandes** : Édition des commandes personnalisées +- **Modération** : Outils de gestion communautaire + +### Surveillance +- **Zabbix Agent 2** : Monitoring avancé *(non testé)* +- **Métriques** : Santé du bot et uptime + +## Installation + +### Prérequis +- [Docker Engine](https://docs.docker.com/engine/install/) ou [Docker Desktop](https://docs.docker.com/desktop/) +- Token Discord pour le bot + +### Démarrage rapide -1. Clonez le dépôt ```bash -git clone https://git.favrep.ch/lapatatedouce/MamieHenrriette -cd MamieHenrriette +# 1. Cloner le projet +git clone https://github.com/skylanix/MamieHenriette.git ``` -2. Copiez le fichier de configuration ```bash -cp .env.example .env +cd MamieHenriette ``` -3. Éditez le fichier `.env` avec vos paramètres ```bash -nano .env +# 2. Lancer avec Docker +docker compose up --build -d ``` -4. Démarrez le conteneur Docker +### Configuration + +1. **Interface web** : Accédez à http://localhost +2. **Token Discord** : Section "Configurations" +3. **Humeurs** : Définir les statuts du bot +4. **Canaux** : Configurer les notifications + +> ⚠️ **Important** : Après avoir configuré le token Discord, les humeurs et autres fonctionnalités via l'interface web, **redémarrez le conteneur** pour que les changements soient pris en compte : +> ```bash +> docker compose restart mamiehenriette +> ``` + +### Commandes Docker utiles -**Mode développement (avec logs):** ```bash -docker-compose up --build +# Logs en temps réel +docker compose logs -f mamiehenriette ``` -**Mode production (en arrière-plan):** ```bash -docker-compose up --build -d +# Logs d'un conteneur en cours d'exécution +docker logs -f mamiehenriette ``` -**Voir les logs:** ```bash -docker-compose logs -f discord-bot +# Redémarrer +docker compose restart mamiehenriette ``` -**Arrêter le conteneur:** ```bash -docker-compose down +# Arrêter +docker compose down ``` -## 🔧 Configuration +## Configuration avancée -### Variables d'environnement principales +### Variables d'environnement -- `TOKEN`: Votre token Discord (obligatoire) -- `STATUS`: Statut initial (défaut: online) -- `INTERVAL`: Intervalle de changement de statut (défaut: 3600 secondes) +```yaml +environment: + - ENABLE_ZABBIX=false # Surveillance (non testée) + - ZABBIX_SERVER=localhost + - ZABBIX_HOSTNAME=MamieHenriette +``` -### 📊 Configuration Zabbix (optionnelle) +### Interface d'administration -- `ENABLE_ZABBIX`: Activer la surveillance Zabbix (défaut: false) -- `ZABBIX_SERVER`: Adresse du serveur Zabbix -- `ZABBIX_HOSTNAME`: Nom d'hôte pour identifier le bot -- `ZABBIX_PORT`: Port d'exposition Zabbix (défaut: 10050) +| Section | Fonction | +|---------|----------| +| **Configurations** | Tokens et paramètres généraux | +| **Humeurs** | Gestion des statuts Discord | +| **Commandes** | Commandes personnalisées | +| **Modération** | Outils de gestion | -#### Métriques surveillées par Zabbix +## Architecture du projet -- Statut du bot Discord -- Temps de fonctionnement (uptime) -- Utilisation mémoire -- Erreurs et avertissements dans les logs -- Connectivité à Discord +### Structure des modules -#### Activation de Zabbix +``` +├── database/ # Couche données +│ ├── models.py # Modèles ORM +│ ├── helpers.py # Utilitaires BDD +│ └── schema.sql # Structure initiale +│ +├── discordbot/ # Module Discord +│ └── __init__.py # Bot et handlers +│ +└── webapp/ # Interface d'administration + ├── static/ # Assets statiques + ├── templates/ # Vues HTML + └── *.py # Contrôleurs par section +``` -Dans votre fichier `.env` : +### Composants principaux + +| Fichier | Rôle | +|---------|------| +| `run-web.py` | Point d'entrée principal | +| `start.sh` | Script de démarrage Docker | +| `docker-compose.yml` | Configuration des services | +| `requirements.txt` | Dépendances Python | + +## Spécifications techniques + +### Base de données (SQLite) +- **Configuration** : Paramètres et tokens +- **Humeur** : Statuts Discord rotatifs +- **Message** : Messages périodiques *(planifié)* +- **GameBundle** : Historique Humble Bundle + +### Architecture multi-thread +- **Thread 1** : Interface web Flask (port 5000) +- **Thread 2** : Bot Discord et tâches automatisées + +### Dépendances principales +``` +discord.py # API Discord +flask # Interface web +requests # Client HTTP +waitress # Serveur WSGI +``` + +## Développement + +### Installation locale ```bash -ENABLE_ZABBIX=true -ZABBIX_SERVER=votre-serveur-zabbix.com -ZABBIX_HOSTNAME=MamieHenriette +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt +python run-web.py ``` -### Fichier `statuts.txt` - -Créez un fichier `statuts.txt` avec vos statuts, un par ligne. - -Exemple : -``` -Surveiller le serveur -Mamie est là ! -En mode supervision -``` - -## 📋 Dépendances - -- discord.py==2.3.2 -- python-dotenv==1.0.0 +### Contribution +1. Fork du projet +2. Branche feature +3. Pull Request --- -# 🖥️ Installation environnement de développement - -## Installation des dépendances système - -```bash -sudo apt install python3 python3-pip -``` - -## Création de l'environnement Python local - -Dans le dossier du projet : - -```bash -python3 -m venv .venv -``` - -Puis activer l'environnement : - -```bash -source .venv/bin/activate -``` - -## Installation des dépendances Python - -```bash -pip install -r requirements.txt -``` - -## Exécution - -```bash -python3 run-web.py -``` - -# Structure du projet - -``` -. -|-- database : module de connexion à la BDD -| |-- __init.py__ -| |-- models.py : contient les pojo représentant chaque table -| |-- schema.sql : contient un scrip sql d'initialisation de la bdd, celui-ci doit être réentrant -| -|-- discordbot : module de connexion à discord -| |-- __init.py__ -| -|-- webapp : module du site web d'administration -| |-- static : Ressource fixe directement accessible par le navigateir -| | |-- css -| | |-- ... -| | -| |-- template : Fichier html -| | |-- template.html : structure globale du site -| | |-- commandes.html : page de gestion des commandes -| | |-- ... -| | -| |-- __init.py__ -| |-- index.py : controller de la page d'acceuil -| |-- commandes.py : controller de gestion des commandes -| |-- ... -| -|-- run-web.py : launcher -``` \ No newline at end of file +*Mamie Henriette vous surveille ! 👵👀* \ No newline at end of file diff --git a/bot.py b/bot.py deleted file mode 100755 index d9fe373..0000000 --- a/bot.py +++ /dev/null @@ -1,114 +0,0 @@ -import discord -import json -import random -import asyncio -import logging -import os - -class DiscordStatusBot: - def __init__(self): - # Configuration des logs - logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s') - - # Charger la configuration à partir des variables d'environnement - self.config = self.charger_configuration() - if not self.config: - logging.error("Impossible de charger la configuration") - exit(1) - - # Configuration des intents - intents = discord.Intents.default() - intents.message_content = False - - # Création du client - self.client = discord.Client(intents=intents) - - # Événements - self.setup_events() - - def charger_configuration(self): - """Chargement de la configuration à partir des variables d'environnement""" - config = { - 'token': os.getenv('TOKEN'), - 'status': os.getenv('STATUS', 'online'), - 'interval': int(os.getenv('INTERVAL', 60)) - } - - if not config['token']: - logging.error("Token non fourni") - return None - - return config - - def charger_statuts(self): - """Chargement des statuts depuis le fichier""" - try: - with open('/app/statuts.txt', 'r', encoding='utf-8') as fichier: - return [ligne.strip() for ligne in fichier.readlines() if ligne.strip()] - except FileNotFoundError: - logging.error("Fichier de statuts non trouvé") - return [] - - def setup_events(self): - """Configuration des événements du bot""" - @self.client.event - async def on_ready(): - logging.info(f'Bot connecté : {self.client.user}') - self.client.loop.create_task(self.changer_statut()) - - # Déplacez changer_statut à l'extérieur de setup_events - async def changer_statut(self): - """Changement cyclique du statut""" - await self.client.wait_until_ready() - statuts = self.charger_statuts() - if not statuts: - logging.warning("Aucun statut disponible") - return - - # Mapping des status Discord - status_mapping = { - 'online': discord.Status.online, - 'idle': discord.Status.idle, - 'dnd': discord.Status.dnd, - 'invisible': discord.Status.invisible - } - - # Récupérer le status depuis la configuration - status_discord = status_mapping.get(self.config.get('status', 'online'), discord.Status.online) - - while not self.client.is_closed(): - try: - # Sélection du statut - statut = random.choice(statuts) - - # Changement de statut avec custom activity - await self.client.change_presence( - status=status_discord, - activity=discord.CustomActivity(name=statut) - ) - logging.info(f"Statut changé : {statut}") - - # Délai entre les changements - await asyncio.sleep(self.config.get('interval', 60)) - except Exception as e: - logging.error(f"Erreur lors du changement de statut : {e}") - await asyncio.sleep(30) # Attente en cas d'erreur - - def executer(self): - """Lancement du bot""" - try: - if self.config and 'token' in self.config: - self.client.run(self.config['token']) - else: - logging.error("Token non trouvé dans la configuration") - except discord.LoginFailure: - logging.error("Échec de connexion - Vérifiez votre token") - except Exception as e: - logging.error(f"Erreur lors du lancement : {e}") - -def main(): - bot = DiscordStatusBot() - bot.executer() - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/database/helpers.py b/database/helpers.py new file mode 100644 index 0000000..319285e --- /dev/null +++ b/database/helpers.py @@ -0,0 +1,32 @@ + +from database import db +from database.models import Configuration + +class ConfigurationHelper: + def getValue(self, key:str) : + conf = Configuration.query.filter_by(key=key).first() + if conf == None: + return None + if (key.endswith('_enable')) : + return conf.value in ['true', '1', 'yes', 'on'] + return conf.value + + def getIntValue(self, key:str) : + conf = Configuration.query.filter_by(key=key).first() + if conf == None: + return 0 + return int(conf.value) + + def createOrUpdate(self, key:str, value) : + conf = Configuration.query.filter_by(key=key).first() + if (key.endswith('_enable')) : + value = value in ['true', '1', 'yes', 'on'] + if conf : + conf.value = value + else : + conf = Configuration(key = key, value = value) + db.session.add(conf) + + + + diff --git a/database/models.py b/database/models.py index 05f1ad5..020a25e 100644 --- a/database/models.py +++ b/database/models.py @@ -9,6 +9,11 @@ class Humeur(db.Model): enable = db.Column(db.Boolean, default=True) text = db.Column(db.String(256)) +class GameBundle(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(256)) + json = db.Column(db.String(1024)) + class Message(db.Model): id = db.Column(db.Integer, primary_key=True) enable = db.Column(db.Boolean, default=False) diff --git a/database/schema.sql b/database/schema.sql index 0ba37a3..7a88e61 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -4,15 +4,21 @@ CREATE TABLE IF NOT EXISTS `configuration` ( `value` VARCHAR(512) NOT NULL ); +CREATE TABLE IF NOT EXISTS `game_bundle` ( + id INTEGER PRIMARY KEY, + name VARCHAR(256) NOT NULL, + json VARCHAR(1024) NOT NULL +); + +CREATE TABLE IF NOT EXISTS `humeur` ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + `enable` BOOLEAN NOT NULL DEFAULT TRUE, + `text` VARCHAR(256) NULL +); + CREATE TABLE IF NOT EXISTS `message` ( id INTEGER PRIMARY KEY AUTOINCREMENT, `enable` BOOLEAN NOT NULL DEFAULT FALSE, `text` VARCHAR(256) NULL, periodicity INTEGER NULL ); - -CREATE TABLE IF NOT EXISTS `humeur` ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - `enable` BOOLEAN NOT NULL DEFAULT TRUE, - `text` VARCHAR(256) NULL -); diff --git a/discordbot/__init__.py b/discordbot/__init__.py index 6bbee83..6d2dae8 100644 --- a/discordbot/__init__.py +++ b/discordbot/__init__.py @@ -1,34 +1,65 @@ -import random -import discord -# import os -import logging import asyncio -from webapp import webapp -from database.models import Configuration, Humeur +import datetime +import discord +import json +import logging +import random +import requests + +from database import db +from database.helpers import ConfigurationHelper +from database.models import Configuration, GameBundle, Humeur class DiscordBot(discord.Client): async def on_ready(self): logging.info(f'Logged in as {self.user} (ID: {self.user.id})') for c in self.get_all_channels() : logging.info(f'{c.id} {c.name}') + self.loop.create_task(self.updateStatus()) - # await self.get_channel(1123512494468644984).send("essai en python") + self.loop.create_task(self.updateHumbleBundle()) async def updateStatus(self): - # from database.models import Humeur - humeur = random.choice(Humeur.query.all()) - if humeur != None: - logging.info(f'changement de status {humeur.text}') - await self.change_presence(status = discord.Status.online, activity = discord.CustomActivity(humeur.text)) - await asyncio.sleep(60) + while not self.is_closed(): + humeurs = Humeur.query.all() + if len(humeurs)>0 : + humeur = random.choice(humeurs) + if humeur != None: + logging.info(f'changement de status {humeur.text}') + await self.change_presence(status = discord.Status.online, activity = discord.CustomActivity(humeur.text)) + # 10 minutes TODO à rendre configurable + await asyncio.sleep(10*60) + async def updateHumbleBundle(self): + while not self.is_closed(): + if ConfigurationHelper().getValue('humble_bundle_enable') and ConfigurationHelper().getIntValue('humble_bundle_channel') != 0 : + response = requests.get("http://hexas.shionn.org/humble-bundle/json", headers={ "Content-Type": "application/json" }) + if response.status_code == 200: + bundle = response.json() + if GameBundle.query.filter_by(id=bundle['id']).first() == None : + choice = bundle['choices'][0] + date = datetime.datetime.fromtimestamp(bundle['endDate']/1000,datetime.UTC).strftime("%d %B %Y") + message = f"@here **Humble Bundle** propose un pack de jeu [{bundle['name']}]({bundle['url']}) contenant :\n" + for game in choice["games"]: + message += f"- {game}\n" + message += f"Pour {choice['price']}€, disponible jusqu'au {date}." + await self.get_channel(ConfigurationHelper().getIntValue('humble_bundle_channel')).send(message) + db.session.add(GameBundle(id=bundle['id'], name=bundle['name'], json = json.dumps(bundle))) + db.session.commit() + else: + logging.error(f"Erreur de connexion {response.status_code}") + else: + logging.info('Humble bundle est désactivé') + # toute les 30 minutes + await asyncio.sleep(30*60) + def begin(self) : - with webapp.app_context(): - token = Configuration.query.filter_by(key='discord_token').first() - if token : - self.run(token.value) - else : - logging.error('pas de token on ne lance pas discord') + token = Configuration.query.filter_by(key='discord_token').first() + if token : + self.run(token.value) + else : + logging.error('pas de token on ne lance pas discord') intents = discord.Intents.default() bot = DiscordBot(intents=intents) + diff --git a/docker-compose.yml b/docker-compose.yml index f6f46a0..c5f75bf 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,15 @@ services: - discord-bot: + mamiehenriette: container_name: MamieHenriette build: . restart: on-failure environment: - - TOKEN=VOTRE_TOKEN_DISCORD_ICI - - STATUS=online - - INTERVAL=3600 - ENABLE_ZABBIX=false - ZABBIX_SERVER=zabbix-server.example.com - ZABBIX_HOSTNAME=mamie-henriette-bot volumes: - - ./statuts.txt:/app/statuts.txt - # ports: + - ./instance:/app/instance + + ports: + - 80:5000 # - "10050:10050" # Décommentez si ENABLE_ZABBIX=true \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index ab7ca91..9fecc34 100755 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ audioop-lts; python_version>='3.13' flask>=2.3.2 flask-sqlalchemy>=3.0.3 -waitress>=3.0.2 \ No newline at end of file +waitress>=3.0.2 +requests>=2.32.4 \ No newline at end of file diff --git a/run-web.py b/run-web.py index a619128..218fe2b 100644 --- a/run-web.py +++ b/run-web.py @@ -1,25 +1,28 @@ -# -# import discordbot -import multiprocessing +import locale import logging +import threading +from webapp import webapp +from discordbot import bot def start_server(): logging.info("Start Web Serveur") - from webapp import webapp from waitress import serve serve(webapp, host="0.0.0.0", port=5000) def start_discord_bot(): logging.info("Start Discord Bot") - from discordbot import bot - bot.begin() + with webapp.app_context(): + bot.begin() if __name__ == '__main__': + locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8') + jobs = [] - jobs.append(multiprocessing.Process(target=start_server)) - jobs.append(multiprocessing.Process(target=start_discord_bot)) + jobs.append(threading.Thread(target=start_discord_bot)) + jobs.append(threading.Thread(target=start_server)) for job in jobs: job.start() for job in jobs: job.join() + diff --git a/start.sh b/start.sh index 4371cb5..b6cc32c 100644 --- a/start.sh +++ b/start.sh @@ -18,4 +18,4 @@ else fi echo "Démarrage du bot Discord..." -exec python3 bot.py \ No newline at end of file +exec /app/venv/bin/python run-web.py \ No newline at end of file diff --git a/statuts.txt b/statuts.txt deleted file mode 100755 index bf36966..0000000 --- a/statuts.txt +++ /dev/null @@ -1,22 +0,0 @@ -STEvE galère un peu, mais moi je gère le bazar. -Sans mamie, vous seriez bien vite paumés. -Ici, c’est mamie qui veille, alors écoutez un peu. -STEvE dort, moi je fais tourner la baraque. -J’aime râler, mais c’est pour vous réveiller un peu. -Restez sages, sinon mamie va grogner un peu. -Les malins, faites-moi plaisir, écoutez mamie. -Jamais le bazar ne s’installe, je veille au grain. -C’est moi qui tiens la maison. -Vous aimez STEvE ? Moi, je vous tolère. -Gardez votre calme, mamie veille sur vous. -Quand STEvE foire, je suis là pour arranger ça. -Suivez STEvE, mais surtout ne perdez pas mamie de vue. -STEvE rêve, moi je travaille en coulisses. -Ecoutez mamie, c’est pour votre bien. -Pas d’embrouille, ou mamie va devoir intervenir. -STEvE dort, mais mamie veille toujours. -Vous râlez ? Moi aussi, mais on fait avec. -STEvE prend son temps, moi je veille au grain. -Pas de bazar, mamie préfère le calme. -STEvE est parfois perdu, mais mamie est là. -Le serveur est calme, grâce à mamie. \ No newline at end of file diff --git a/webapp/configurations.py b/webapp/configurations.py index d8d6c0f..e629e69 100644 --- a/webapp/configurations.py +++ b/webapp/configurations.py @@ -1,19 +1,24 @@ from flask import render_template, request, redirect, url_for from webapp import webapp from database import db -from database.models import Configuration +from database.helpers import ConfigurationHelper +from discordbot import bot +from discord import TextChannel @webapp.route("/configurations") def openConfigurations(): - return render_template("configurations.html") + channels = [] + for channel in bot.get_all_channels(): + if isinstance(channel, TextChannel): + channels.append(channel) + return render_template("configurations.html", configuration = ConfigurationHelper(), channels = channels) -@webapp.route('/configurations/set/', methods=['POST']) -def setConfiguration(key): - conf = Configuration.query.filter_by(key=key).first() - if conf : - conf.value = request.form['value'] - else : - conf = Configuration(key = key, value = request.form['value']) - db.session.add(conf) +@webapp.route("/configurations/update", methods=['POST']) +def updateConfiguration(): + for key in request.form : + ConfigurationHelper().createOrUpdate(key, request.form.get(key)) + # Je fait ca car html n'envoi pas le parametre de checkbox quand il est décoché + if (request.form.get("humble_bundle_channel") != None and request.form.get("humble_bundle_enable") == None) : + ConfigurationHelper().createOrUpdate('humble_bundle_enable', False) db.session.commit() return redirect(url_for('openConfigurations')) diff --git a/webapp/templates/configurations.html b/webapp/templates/configurations.html index 075c718..f2e6038 100644 --- a/webapp/templates/configurations.html +++ b/webapp/templates/configurations.html @@ -3,10 +3,27 @@ {% block content %}

Configuration de Mamie.

+

Humble Bundle

+
+ + + + + + +
+

Api

-
- - + + +

Nécéssite un redémarrage