Files
epicthefamily/family.py
2025-04-20 22:08:44 +02:00

203 lines
6.7 KiB
Python

import json
import os
from typing import Dict, List, Optional
class FamilyManager:
def __init__(self, file_path: str):
self.file_path = file_path
if not os.path.exists(file_path):
self._init_empty_file()
def _init_empty_file(self):
"""Initialise un fichier JSON vide avec la structure attendue"""
with open(self.file_path, "w") as f:
json.dump({
"members": {},
"couples": [],
"roots": []
}, f, indent=2)
def _load(self) -> Dict:
"""Charge les données depuis le fichier JSON"""
with open(self.file_path) as f:
return json.load(f)
def _save(self, data: Dict):
"""Sauvegarde les données dans le fichier JSON"""
with open(self.file_path, "w") as f:
json.dump(data, f, indent=2)
def add_member(self, member_id: str, member_name: str, avatar_url: str = None):
"""
Ajoute ou met à jour un membre
:param member_id: ID Discord du membre
:param member_name: Nom d'affichage
:param avatar_url: URL de l'avatar (optionnel)
"""
data = self._load()
if str(member_id) not in data["members"]:
data["members"][str(member_id)] = {
"name": member_name,
"avatar": avatar_url,
"parents": []
}
else:
# Mise à jour des informations existantes
data["members"][str(member_id)]["name"] = member_name
if avatar_url:
data["members"][str(member_id)]["avatar"] = avatar_url
self._save(data)
def add_child(self, parent_id: str, child_id: str) -> bool:
"""
Ajoute un lien parent-enfant
:param parent_id: ID du parent
:param child_id: ID de l'enfant
:return: True si succès, False si échec
"""
data = self._load()
# Vérifie que les membres existent
if str(child_id) not in data["members"] or str(parent_id) not in data["members"]:
return False
# Ajoute le parent principal
parent_name = data["members"][str(parent_id)]["name"]
data["members"][str(child_id)]["parents"].append({
"id": str(parent_id),
"name": parent_name
})
# Ajoute le partenaire comme parent secondaire si existe
partner_id = self.get_partner(parent_id)
if partner_id:
partner_name = data["members"].get(partner_id, {}).get("name", "Partenaire")
data["members"][str(child_id)]["parents"].append({
"id": partner_id,
"name": partner_name
})
self._save(data)
return True
def add_couple(self, member1_id: str, member2_id: str) -> bool:
"""
Crée un lien de couple entre deux membres
:return: True si le couple a été ajouté, False s'il existait déjà
"""
data = self._load()
couple = sorted([str(member1_id), str(member2_id)])
if couple not in data["couples"]:
data["couples"].append(couple)
self._save(data)
return True
return False
def get_partner(self, member_id: str) -> Optional[str]:
"""Trouve l'ID du partenaire d'un membre"""
data = self._load()
for couple in data["couples"]:
if str(member_id) in couple:
return couple[0] if couple[1] == str(member_id) else couple[1]
return None
def remove_child(self, parent_id: str, child_id: str) -> bool:
"""
Supprime un lien parent-enfant
:return: True si suppression effectuée, False si lien introuvable
"""
data = self._load()
changed = False
if str(child_id) in data["members"]:
original_count = len(data["members"][str(child_id)]["parents"])
data["members"][str(child_id)]["parents"] = [
p for p in data["members"][str(child_id)]["parents"]
if p["id"] != str(parent_id)
]
changed = len(data["members"][str(child_id)]["parents"]) < original_count
if changed:
self._save(data)
return changed
def remove_member(self, member_id: str) -> bool:
"""Supprime complètement un membre de la famille"""
data = self._load()
member_id = str(member_id)
if member_id not in data["members"]:
return False
# Supprime des couples
data["couples"] = [c for c in data["couples"] if member_id not in c]
# Supprime des racines
if "roots" in data and member_id in data["roots"]:
data["roots"].remove(member_id)
# Supprime le membre
del data["members"][member_id]
# Nettoie les références parentales
for m in data["members"].values():
m["parents"] = [p for p in m["parents"] if p["id"] != member_id]
self._save(data)
return True
def get_member(self, member_id: str) -> Optional[Dict]:
"""Récupère les informations d'un membre"""
data = self._load()
return data["members"].get(str(member_id))
def get_parents(self, member_id: str) -> List[Dict]:
"""Liste les parents d'un membre"""
data = self._load()
return data["members"].get(str(member_id), {}).get("parents", [])
def get_children(self, member_id: str) -> List[str]:
"""Liste les enfants d'un membre"""
data = self._load()
return [
user_id for user_id, info in data["members"].items()
if any(p["id"] == str(member_id) for p in info.get("parents", []))
]
def get_generation(self, member_id: str) -> int:
"""
Calcule la génération d'un membre
:return: 0 pour les racines, 1 pour leurs enfants, etc.
"""
data = self._load()
# Si c'est une racine explicite
if str(member_id) in data.get("roots", []):
return 0
parents = data["members"].get(str(member_id), {}).get("parents", [])
# Si pas de parents => nouvelle racine (gen 0)
if not parents:
return 0
# Calcul basé sur les parents
return 1 + min(
self.get_generation(p["id"])
for p in parents
if p["id"] in data["members"]
)
def get_all_members(self) -> List[str]:
"""Liste tous les IDs des membres enregistrés"""
data = self._load()
return list(data["members"].keys())
def get_roots(self) -> List[str]:
"""Liste toutes les racines"""
data = self._load()
return data.get("roots", [])