220 lines
7.2 KiB
Python
220 lines
7.2 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 set_as_root(self, member_id: str, is_root: bool = True) -> bool:
|
|
"""Définit un membre comme racine ou non"""
|
|
data = self._load()
|
|
if str(member_id) not in data["members"]:
|
|
return False
|
|
|
|
if "roots" not in data:
|
|
data["roots"] = []
|
|
|
|
if is_root and str(member_id) not in data["roots"]:
|
|
data["roots"].append(str(member_id))
|
|
elif not is_root and str(member_id) in data["roots"]:
|
|
data["roots"].remove(str(member_id))
|
|
|
|
self._save(data)
|
|
return True
|
|
|
|
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(str(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 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", [])
|
|
|
|
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
|