# -*- coding: utf-8 -*- """ Script permettant de générer des fichiers CSV à partir d'agenda Nextcloud contenant un récapitulatif des heures de travail effectué Pour Crealead @author: Jordan @date: 17/11/2022 @TODO: Améliorer la structure du code, pour l'instant c'est un peu moche @TODO: Ajouter des paramètres pour le mois, et le verbose pour avoir des logs @TOOD: README sur l'utilisation du script """ import sys import caldav import json import csv import calendar from datetime import date, datetime, timezone import pytz class EventRow(): def __init__(self): self.title = '' self.start_date = '' self.start_time = '' self.end_date = '' self.end_time = '' self.categories = '' self.location = '' self.description = '' def set_title(self, title): self.title = title def set_start(self, start): self.start_date = start.date() self.start_time = start.time() def set_end(self, end): self.end_date = end.date() self.end_time = end.time() def set_categories(self, categories): self.categories = categories def set_location(self, location): self.location = location def set_description(self, description): self.description = description def get_csv_row(self): """Return CSV row""" return [self.title,self.start_date,self.start_time,self.end_date,self.end_time,self.categories,self.location,self.description] def load_json_config(filename): """Return the config from JSON file""" with open(filename, 'r') as f: config_json = json.load(f) return config_json def init_connection(config): """Return all the calendars from the server""" dav_client = caldav.DAVClient(url=config['caldav_url'], username=config['username'], password=config['password']) try: dav_connection = dav_client.principal() except Exception as e: print("Une erreur a eu lieu pendant la connexion : ", e) sys.exit() calendars_server = dav_connection.calendars() if not calendars_server: print("Aucun calendrier disponible sur le compte !") sys.exit() return calendars_server def link_calendars(config, calendars_server): """Do the link between calendar we search (from the config) and calendar available on the remote server""" calendars_find = [] for calendar_config in config['calendars']: cpt = 0 for calendar_server in calendars_server: if calendar_config['calendar_name'] in calendar_server.name: cpt += 1 calendar_find = calendar_config calendar_find['calendar_server'] = calendar_server calendars_find.append(calendar_find) if not cpt: print("Le calendrier nommé " + calendar_config['calendar_name'] + " pour le fichier " + calendar_config['csv_name'] + " n'est pas trouvé sur le serveur !") sys.exit() elif cpt >= 2: print("Il y a plusieurs calendriers sur le serveur correspondant au calendrier nommé " + calendar_config['calendar_name'] + " pour le fichier " + calendar_config['csv_name'] + " !") print(calendars_find) sys.exit() return calendars_find def split_data(data): """Return string splitted by ';' separator""" return data.split(':') def datetime_format(date_str): """Return date formated""" try: # Nextcloud Format date_formated = datetime.strptime(date_str, '%Y%m%dT%H%M%SZ') except: # Zimbra format date_formated = datetime.strptime(date_str, '%Y%m%d') paris_tz = pytz.timezone('Europe/Paris') date_formated = date_formated.replace(tzinfo=timezone.utc).astimezone(paris_tz) #date_formated = date_formated.astimezone(paris_tz) return date_formated def get_all_events(config, calendars_find): """Return row with the specific information we need to write it in CSV""" calendars_to_write = [] for calendar_find in calendars_find: print(calendar_find['csv_name'], "...") events_fetched = calendar_find['calendar_server'].date_search(start=datetime(config['year_start'], config['month_start'], config['day_start']), end=datetime(config['year_end'], config['month_end'], config['day_end']), expand=True) event_rows = [] for event in events_fetched: event_fields = list(map(split_data, event.data.splitlines())) # Fix problem #2023022110004936 has = False for sub in event_fields: if 'SUMMARY' in sub: has = True break if not has: continue event_row = EventRow() for field in ['SUMMARY', 'DTSTART', 'DTEND', 'CATEGORIES', 'LOCATION', 'DESCRIPTION']: for event_field in event_fields: if field in event_field[0]: if field == "SUMMARY": event_row.set_title(event_field[1]) elif field == "DTSTART": date = datetime_format(event_field[1]) event_row.set_start(date) elif field == "DTEND": date = datetime_format(event_field[1]) event_row.set_end(date) elif field == "CATEGORIES": event_row.set_categories(event_field[1]) elif field == "LOCATION": event_row.set_location(event_field[1]) elif field == "DESCRIPTION": event_row.set_description(event_field[1]) 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")) calendars_to_write.append({'csv_name' : calendar_find['csv_name'], 'line' : sorted_rows}) return calendars_to_write def write_csv(filename, rows): """Write CSV file""" with open(filename, 'w') as file: writer = csv.writer(file, delimiter=';') csv_title= ['Titre', 'Date debut', 'Heure debut', 'Date fin', 'Heure fin', 'Categories', 'Emplacement', 'Description'] writer.writerow(csv_title) for row in rows: writer.writerow(row.get_csv_row()) if __name__ == "__main__": # Load config config = load_json_config("./config.json") # Init connection with server calendars_server = init_connection(config) # Link calendars in config with calendar from server calendars_find = link_calendars(config, calendars_server) # Get all events calendars_to_write = get_all_events(config, calendars_find) # Write CSV for calendar_to_write in calendars_to_write: write_csv(calendar_to_write['csv_name'], calendar_to_write['line'])