Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69d7dce842 | |||
| dadb1d4f23 |
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
env/*
|
env/*
|
||||||
config.json
|
config.json
|
||||||
config.json.orig
|
config.json.*
|
||||||
|
csv/*
|
||||||
|
|||||||
+9
-2
@@ -20,7 +20,8 @@ import csv
|
|||||||
import calendar
|
import calendar
|
||||||
from datetime import date, datetime, timezone
|
from datetime import date, datetime, timezone
|
||||||
import pytz
|
import pytz
|
||||||
|
from urllib.parse import unquote
|
||||||
|
import re
|
||||||
|
|
||||||
class EventRow():
|
class EventRow():
|
||||||
|
|
||||||
@@ -170,7 +171,7 @@ def get_all_events(config, calendars_find):
|
|||||||
elif field == "LOCATION":
|
elif field == "LOCATION":
|
||||||
event_row.set_location(event_field[1])
|
event_row.set_location(event_field[1])
|
||||||
elif field == "DESCRIPTION":
|
elif field == "DESCRIPTION":
|
||||||
event_row.set_description(event_field[1])
|
event_row.set_description(clean_description(event_field[1]))
|
||||||
event_rows.append(event_row)
|
event_rows.append(event_row)
|
||||||
|
|
||||||
sorted_rows = sorted(event_rows, key=lambda l: datetime.strptime(str(l.start_date)+'T'+str(l.start_time), "%Y-%m-%dT%H:%M:%S"))
|
sorted_rows = sorted(event_rows, key=lambda l: datetime.strptime(str(l.start_date)+'T'+str(l.start_time), "%Y-%m-%dT%H:%M:%S"))
|
||||||
@@ -179,6 +180,12 @@ def get_all_events(config, calendars_find):
|
|||||||
|
|
||||||
return calendars_to_write
|
return calendars_to_write
|
||||||
|
|
||||||
|
def clean_description(value):
|
||||||
|
if value.startswith("text/html,"):
|
||||||
|
value = value[len("text/html,"):]
|
||||||
|
value = unquote(value)
|
||||||
|
value = re.sub(r'<[^>]+>', '', value)
|
||||||
|
return value.strip().strip('"')
|
||||||
|
|
||||||
def write_csv(filename, rows):
|
def write_csv(filename, rows):
|
||||||
"""Write CSV file"""
|
"""Write CSV file"""
|
||||||
|
|||||||
+10
-37
@@ -139,13 +139,10 @@ def get_client_uuid_by_name(client_name, user_id):
|
|||||||
query = ("select uuid from oc_timemanager_client where name=\""+client_name+"\" AND user_id=\""+user_id+"\"")
|
query = ("select uuid from oc_timemanager_client where name=\""+client_name+"\" AND user_id=\""+user_id+"\"")
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
row = cursor.fetchone()
|
client_uuid = cursor.fetchone()[0]
|
||||||
save_db()
|
save_db()
|
||||||
|
|
||||||
if not row:
|
return client_uuid.decode('utf-8')
|
||||||
return None
|
|
||||||
|
|
||||||
return row[0].decode('utf-8')
|
|
||||||
|
|
||||||
|
|
||||||
def get_project_uuid_by_name(project_name, client_uuid, user_id):
|
def get_project_uuid_by_name(project_name, client_uuid, user_id):
|
||||||
@@ -267,6 +264,7 @@ def create_project(name, client_uuid):
|
|||||||
#print(json.dumps(response.json(), indent=1))
|
#print(json.dumps(response.json(), indent=1))
|
||||||
else:
|
else:
|
||||||
print("Erreur de création project")
|
print("Erreur de création project")
|
||||||
|
print(response)
|
||||||
print(response.reason)
|
print(response.reason)
|
||||||
|
|
||||||
def create_client(name):
|
def create_client(name):
|
||||||
@@ -314,28 +312,15 @@ def create_client(name):
|
|||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(url, data=json.dumps(req_data), headers=headers)
|
response = requests.post(url, data=json.dumps(req_data), headers=headers)
|
||||||
|
|
||||||
# Vérification de la réponse
|
# Vérification de la réponse
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
try:
|
pass
|
||||||
resp = response.json()
|
#print("Client créé avec succès.")
|
||||||
# Tenter d'extraire l'UUID renvoyé par l'API (structure attendue)
|
#print(json.dumps(response.json(), indent=1))
|
||||||
client_uuid = None
|
|
||||||
if isinstance(resp, dict):
|
|
||||||
client_created = resp.get('data', {}).get('clients', {}).get('created', [])
|
|
||||||
if client_created and isinstance(client_created, list):
|
|
||||||
client_uuid = client_created[0].get('uuid')
|
|
||||||
|
|
||||||
if client_uuid:
|
|
||||||
return client_uuid
|
|
||||||
# si pas d'uuid dans la réponse, retourner None (le caller gérera)
|
|
||||||
return None
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
else:
|
else:
|
||||||
print("Erreur de création client")
|
print("Erreur de création client")
|
||||||
print(response.reason)
|
print(response.reason)
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def insert_task_time(name, project_name, client_name, task_uuid, user_id, dstart, hstart, dend, hend):
|
def insert_task_time(name, project_name, client_name, task_uuid, user_id, dstart, hstart, dend, hend):
|
||||||
@@ -438,23 +423,11 @@ for user_info in config['calendars']:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Description => Client
|
# Description => Client
|
||||||
client_uuid = None
|
|
||||||
if not client_exist_by_name(client_name, user_id):
|
if not client_exist_by_name(client_name, user_id):
|
||||||
print("Création du client {}".format(client_name))
|
print("Création du client {}".format(client_name))
|
||||||
created_uuid = create_client(client_name)
|
create_client(client_name)
|
||||||
if created_uuid:
|
|
||||||
client_uuid = created_uuid
|
client_uuid = get_client_uuid_by_name(client_name, user_id)
|
||||||
else:
|
|
||||||
# tentative de récupération depuis la base au cas où l'API a créé l'entrée
|
|
||||||
client_uuid = get_client_uuid_by_name(client_name, user_id)
|
|
||||||
if not client_uuid:
|
|
||||||
print("Erreur: impossible d'obtenir l'UUID du client '{}' après création, saut.".format(client_name))
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
client_uuid = get_client_uuid_by_name(client_name, user_id)
|
|
||||||
if not client_uuid:
|
|
||||||
print("Erreur: le client '{}' existe mais son UUID est introuvable, saut.".format(client_name))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Categories => Project
|
# Categories => Project
|
||||||
if not project_exist_by_name(project_name, client_uuid, user_id):
|
if not project_exist_by_name(project_name, client_uuid, user_id):
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Chaque entrée doit contenir au minimum :
|
|||||||
- `user_name` : login Nextcloud utilisé pour authentifier les requêtes,
|
- `user_name` : login Nextcloud utilisé pour authentifier les requêtes,
|
||||||
- `api_password` : mot de passe ou mot de passe d'application Nextcloud.
|
- `api_password` : mot de passe ou mot de passe d'application Nextcloud.
|
||||||
|
|
||||||
|
> Il est important de générer la clé API en s'étant connecté avec l'identifiant et non l'email car le script user_name utilise le champ "user_name" pour faire des vérifications en bases de données avant d'ajouter des données.
|
||||||
|
|
||||||
Colonnes CSV utilisées
|
Colonnes CSV utilisées
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source env/bin/activate
|
||||||
|
python3 remove-users-data-timemanager.py $1
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import csv
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import re
|
||||||
|
import base64
|
||||||
|
import sys
|
||||||
|
import mysql.connector
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Config
|
||||||
|
##########################################
|
||||||
|
# Récupération de la config
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
mydb = mysql.connector.connect(
|
||||||
|
host=config['db_host'],
|
||||||
|
user=config['db_user'],
|
||||||
|
password=config['db_password'],
|
||||||
|
database=config['db_database']
|
||||||
|
)
|
||||||
|
cursor = mydb.cursor(buffered=True)
|
||||||
|
|
||||||
|
# Argument --yes pour auto-valider toutes les suppressions
|
||||||
|
valid_args = {'-y', '--yes'}
|
||||||
|
extra_args = [arg for arg in sys.argv[1:] if arg not in valid_args]
|
||||||
|
|
||||||
|
if extra_args:
|
||||||
|
print(f"Erreur : argument(s) non reconnu(s) : {' '.join(extra_args)}")
|
||||||
|
print(f"Usage : python {sys.argv[0]} [--yes | -y]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
auto_confirm = bool(set(sys.argv[1:]) & valid_args)
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Fonctions
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
def check_users_exist(user_id):
|
||||||
|
"""Vérifie si l'utilisateur existe dans oc_users."""
|
||||||
|
cursor.execute("SELECT uid FROM oc_users WHERE uid = %s", (user_id,))
|
||||||
|
return cursor.fetchone() is not None
|
||||||
|
|
||||||
|
def remove_row_on_table_for_user(user_id, table):
|
||||||
|
"""Supprime toutes les entrées d'une table pour un utilisateur donné."""
|
||||||
|
query = f"DELETE FROM `{table}` WHERE user_id = %s"
|
||||||
|
cursor.execute(query, (user_id,))
|
||||||
|
affected = cursor.rowcount
|
||||||
|
mydb.commit()
|
||||||
|
print(f" [{table}] {affected} ligne(s) supprimée(s)")
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Main
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
tables = [
|
||||||
|
"oc_timemanager_client",
|
||||||
|
"oc_timemanager_commit",
|
||||||
|
"oc_timemanager_project",
|
||||||
|
"oc_timemanager_task",
|
||||||
|
"oc_timemanager_time"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Listing de tous les utilisateurs configurés avant toute action
|
||||||
|
print("==========================================")
|
||||||
|
print("Utilisateurs configurés dans config.json :")
|
||||||
|
print("==========================================")
|
||||||
|
valid_users = []
|
||||||
|
for user_info in config['calendars']:
|
||||||
|
user_id = user_info.get('user_name', '')
|
||||||
|
if not user_id:
|
||||||
|
print(f" ⚠ [{user_id or '???'}] — infos de connexion incomplètes, ignoré")
|
||||||
|
continue
|
||||||
|
exists = check_users_exist(user_id)
|
||||||
|
status = "✔ existe en BDD" if exists else "✘ introuvable en BDD"
|
||||||
|
print(f" • {user_id} — {status}")
|
||||||
|
if exists:
|
||||||
|
valid_users.append(user_info)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
if not valid_users:
|
||||||
|
print("Aucun utilisateur valide à traiter. Fin du script.")
|
||||||
|
cursor.close()
|
||||||
|
mydb.close()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if auto_confirm:
|
||||||
|
print("Mode auto-confirmation activé (--yes) : toutes les suppressions seront effectuées sans demande.\n")
|
||||||
|
|
||||||
|
# Traitement par utilisateur
|
||||||
|
for user_info in valid_users:
|
||||||
|
user_id = user_info['user_name']
|
||||||
|
print("==========================================")
|
||||||
|
print(f"User : {user_id}")
|
||||||
|
print("==========================================")
|
||||||
|
|
||||||
|
if auto_confirm:
|
||||||
|
confirmed = True
|
||||||
|
else:
|
||||||
|
reponse = input(f"\nSupprimer toutes les données TimeManager de '{user_id}' ? [o/N] : ").strip().lower()
|
||||||
|
confirmed = reponse in ('o', 'oui', 'y', 'yes')
|
||||||
|
|
||||||
|
if confirmed:
|
||||||
|
print("Suppression en cours...")
|
||||||
|
for table in tables:
|
||||||
|
remove_row_on_table_for_user(user_id, table)
|
||||||
|
print(f"✔ Données de '{user_id}' supprimées.\n")
|
||||||
|
else:
|
||||||
|
print(f"✘ Suppression annulée pour '{user_id}'.\n")
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
mydb.close()
|
||||||
|
print("Terminé.")
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import csv
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import re
|
||||||
|
import base64
|
||||||
|
import sys
|
||||||
|
import mysql.connector
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Config
|
||||||
|
##########################################
|
||||||
|
# Récupération de la config
|
||||||
|
with open('config.json', 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
|
||||||
|
mydb = mysql.connector.connect(
|
||||||
|
host=config['db_host'],
|
||||||
|
user=config['db_user'],
|
||||||
|
password=config['db_password'],
|
||||||
|
database=config['db_database']
|
||||||
|
)
|
||||||
|
cursor = mydb.cursor(buffered=True)
|
||||||
|
|
||||||
|
# Argument --yes pour auto-valider toutes les suppressions
|
||||||
|
valid_args = {'-y', '--yes'}
|
||||||
|
extra_args = [arg for arg in sys.argv[1:] if arg not in valid_args]
|
||||||
|
|
||||||
|
if extra_args:
|
||||||
|
print(f"Erreur : argument(s) non reconnu(s) : {' '.join(extra_args)}")
|
||||||
|
print(f"Usage : python {sys.argv[0]} [--yes | -y]")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
auto_confirm = bool(set(sys.argv[1:]) & valid_args)
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Fonctions
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
def check_users_exist(user_id):
|
||||||
|
"""Vérifie si l'utilisateur existe dans oc_users."""
|
||||||
|
cursor.execute("SELECT uid FROM oc_users WHERE uid = %s", (user_id,))
|
||||||
|
return cursor.fetchone() is not None
|
||||||
|
|
||||||
|
def remove_row_on_table_for_user(user_id, table):
|
||||||
|
"""Supprime toutes les entrées d'une table pour un utilisateur donné."""
|
||||||
|
query = f"DELETE FROM `{table}` WHERE user_id = %s"
|
||||||
|
cursor.execute(query, (user_id,))
|
||||||
|
affected = cursor.rowcount
|
||||||
|
mydb.commit()
|
||||||
|
print(f" [{table}] {affected} ligne(s) supprimée(s)")
|
||||||
|
|
||||||
|
##########################################
|
||||||
|
# Main
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
tables = [
|
||||||
|
"oc_timemanager_client",
|
||||||
|
"oc_timemanager_commit",
|
||||||
|
"oc_timemanager_project",
|
||||||
|
"oc_timemanager_task",
|
||||||
|
"oc_timemanager_time"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Listing de tous les utilisateurs configurés avant toute action
|
||||||
|
print("==========================================")
|
||||||
|
print("Utilisateurs configurés dans config.json :")
|
||||||
|
print("==========================================")
|
||||||
|
valid_users = []
|
||||||
|
for user_info in config['calendars']:
|
||||||
|
user_id = user_info.get('user_name', '')
|
||||||
|
if not user_id:
|
||||||
|
print(f" ⚠ [{user_id or '???'}] — infos de connexion incomplètes, ignoré")
|
||||||
|
continue
|
||||||
|
exists = check_users_exist(user_id)
|
||||||
|
status = "✔ existe en BDD" if exists else "✘ introuvable en BDD"
|
||||||
|
print(f" • {user_id} — {status}")
|
||||||
|
if exists:
|
||||||
|
valid_users.append(user_info)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
if not valid_users:
|
||||||
|
print("Aucun utilisateur valide à traiter. Fin du script.")
|
||||||
|
cursor.close()
|
||||||
|
mydb.close()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
if auto_confirm:
|
||||||
|
print("Mode auto-confirmation activé (--yes) : toutes les suppressions seront effectuées sans demande.\n")
|
||||||
|
|
||||||
|
# Traitement par utilisateur
|
||||||
|
for user_info in valid_users:
|
||||||
|
user_id = user_info['user_name']
|
||||||
|
print("==========================================")
|
||||||
|
print(f"User : {user_id}")
|
||||||
|
print("==========================================")
|
||||||
|
|
||||||
|
if auto_confirm:
|
||||||
|
confirmed = True
|
||||||
|
else:
|
||||||
|
reponse = input(f"\nSupprimer toutes les données TimeManager de '{user_id}' ? [o/N] : ").strip().lower()
|
||||||
|
confirmed = reponse in ('o', 'oui', 'y', 'yes')
|
||||||
|
|
||||||
|
if confirmed:
|
||||||
|
print("Suppression en cours...")
|
||||||
|
for table in tables:
|
||||||
|
remove_row_on_table_for_user(user_id, table)
|
||||||
|
print(f"✔ Données de '{user_id}' supprimées.\n")
|
||||||
|
else:
|
||||||
|
print(f"✘ Suppression annulée pour '{user_id}'.\n")
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
mydb.close()
|
||||||
|
print("Terminé.")
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ssh execcsv@crl-01.ovea.com
|
||||||
Reference in New Issue
Block a user