210 lines
6.4 KiB
Python
210 lines
6.4 KiB
Python
# -*- 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'])
|