From 73dc43a193ca016b7e3b80e181859b2bc98f0c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20S=C3=A1nchez=20Pizarro?= Date: Tue, 25 Oct 2022 13:10:55 +0200 Subject: [PATCH] google calendar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Omar Sánchez Pizarro --- .gitignore | 3 +- README.md | 13 +++--- autoficher.py | 114 +++++++++++++++++++++++++++++++++++++++-------- requirements.txt | 3 ++ 4 files changed, 108 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 0cffcb3..45cbae9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -config.json \ No newline at end of file +config.json +googleoauth.json \ No newline at end of file diff --git a/README.md b/README.md index 9a35ed2..ce3b260 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,25 @@ Autoficher para Timenet ============================== Que es esto? -------------- - +--------------- Aplicación simple para fichar y desfichar automáticamente Como se usa? --------------- - 1. Ejecutamos `pip3 install -r requirements.txt` para instalar los componentes 2. Ejecutamos `python3 ./autofitcher.py -u -p [-t <0 = Entrada, 1 = Salida>| -bt]` 3. Opcionalmente podemos ponerlo en un Crontab de linux para que se ejecute cada X tiempo y se realize el fichado automatico - Parametros obligatorios --------------- - - -u > Usuario de timenet (Pista Cero = 4c26cc59-ee52-4c47-b7fe-1065a5e5bf84) (Lo he pasado a config.json) - -p > Pin de usuario Tendremos que escojer también entre --basedtime o --type - -bt > No requiere argumento. Esto ficha y desficha basado en la configuración de horas a seguir - - -t <0 = Entrada, 1 = Salida> > Forzamos estado al entrar/salir \ No newline at end of file + - -t <0 = Entrada, 1 = Salida> > Forzamos estado al entrar/salir + +Calendario google +--------------- +Para añadir el uso de calendario de google debemos de descargar el archivo de acceso oauth API y añadirlo +a la raiz del proyecto como "googleoauth.json" se revisará calendario de festivos en españa y calendario autoficher. diff --git a/autoficher.py b/autoficher.py index 04d095b..cc83961 100755 --- a/autoficher.py +++ b/autoficher.py @@ -16,13 +16,21 @@ import json from datetime import datetime import os - import pytz import requests import argparse - import telegram +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from google_auth_oauthlib.flow import InstalledAppFlow +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError + +SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'] + +from dateutil.relativedelta import relativedelta + # Introducimos los argumentos obligatorios y opcionales parser = argparse.ArgumentParser(add_help=False) parser._action_groups.pop() @@ -45,6 +53,11 @@ optionalArgs.add_argument('-ga', '--geoAccuracy', help="GEO Accuracy", type=floa args = parser.parse_args() +if not args.type and not args.basedtime: + print("Hay que indicar al menos un metodo de fichaje -t <0 o 1> o -bt") + exit(20) + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) class AutoFicher(): # URL de la api @@ -59,7 +72,7 @@ class AutoFicher(): try: self.loadConfig() except: - print("No se ha podido cargar el archivo de configuración") + self.sendReport("No se ha podido cargar el archivo de configuración") exit(20) def loadConfig(self): @@ -82,6 +95,7 @@ class AutoFicher(): self.config['geo']['accuracy'] = args.geoAccuracy def sendReport(self, message): + print(message) bot = telegram.Bot(token=self.config['telegram']['token']) bot.sendMessage(chat_id=self.config['telegram']['chat_id'], text=str(message)) @@ -110,6 +124,11 @@ class AutoFicher(): def sendUpdate(self): self.updateTime() + calendar = self.calendarCheck() + if calendar: + self.sendReport("🟥🕐 Comprobación de calendario: " + calendar) + return + typ = 0 if args.basedtime and not args.type: hour = datetime.now().strftime("%H") @@ -123,8 +142,7 @@ class AutoFicher(): elif hour in hOUT: typ = 1 else: - print( - "No se ha fichado ni desfichado ya que estamos en horario laboral, fuerze el estado con el parametro --type <0 = Entrada, 1 = Salida>") + self.sendReport("No se ha fichado ni desfichado ya que estamos en horario laboral, fuerze el estado con el parametro --type <0 = Entrada, 1 = Salida>") else: typ = args.type @@ -142,38 +160,98 @@ class AutoFicher(): response = None if not args.debug: - print("####HACIENDO CHECK####") + self.sendReport("####HACIENDO CHECK####") response = self.post("check", data, self.headers) + else: + self.sendReport('Corriendo en modo debug. No se realizará ninguna acción') + exit(20) try: rj = json.loads(response.text) except: - print("La respuesta al hacer check no es correcta... algo ha pasado :/") + self.sendReport("La respuesta al hacer check no es correcta... algo ha pasado :/") exit(20) - if args.debug: - self.sendReport('Corriendo en modo debug. No se realizará ninguna acción') if response.status_code == 200: if rj['Repeated']: time = datetime.strptime(rj['RepeatedTime'], "%Y-%m-%dT%H:%M:%SZ").replace( tzinfo=pytz.utc).astimezone(pytz.timezone("Europe/Madrid")).strftime("%H:%M") - self.sendReport("🕐 Se ha realizado un marcaje antes a las %s" % time) + self.sendReport("🕐 Ya se ha realizado este marcaje antes a las %s" % time) else: time = datetime.now().astimezone(pytz.timezone("Europe/Madrid")).strftime("%H:%M") - conditional_response = { + conditional_response = [{ "text": "fichado", "emoji": "🕐🏢🏃‍♂️🏡" - } - if typ: - conditional_response = { - "text": "desfichado", - "emoji": "🏡🏃‍♂️🏢🕐" - } - self.sendReport('%s Has %s correctamente a las %s' % (conditional_response['emoji'], conditional_response['text'], time)) + },{ + "text": "desfichado", + "emoji": "🏡🏃‍♂️🏢🕐" + }] + self.sendReport('%s Has %s correctamente a las %s' % (conditional_response[int(typ)]['emoji'], conditional_response[int(typ)]['text'], time)) else: self.sendReport("🟥🕐 No se ha podido fichar, la web no ha devuelto 200 OK") + def calendarCheck(self): + creds = None + configpath = os.path.join(ROOT_DIR, 'googleoauth.json') + if os.path.exists(configpath): + try: + creds = Credentials.from_authorized_user_file(configpath, SCOPES) + except ValueError as error: + print(error) + else: + return False + + + if not creds or not creds.valid: + if creds and creds.expired and creds.refresh_token: + creds.refresh(Request()) + else: + flow = InstalledAppFlow.from_client_secrets_file(configpath, SCOPES) + creds = flow.run_local_server(port=0) + + with open(configpath, 'w') as token: + token.write(creds.to_json()) + + try: + service = build('calendar', 'v3', credentials=creds) + + # Call the Calendar API + now = datetime.utcnow().strftime('%Y-%m-%dT00:00:00Z') # 'Z' indicates UTC time + + now_after_one_day = (datetime.utcnow() + relativedelta(days=1)).strftime('%Y-%m-%dT00:00:00Z') + events_result_autoficher = service.events().list(calendarId='e51d3bfb6b352c48afb8bd7a5d494599cc3eaa686800a856796306f50c6d72fd@group.calendar.google.com', timeMin=now, + timeMax=now_after_one_day, maxResults=10, singleEvents=True, + orderBy='startTime').execute() + events_result_holiday = service.events().list( + calendarId='es.spain#holiday@group.v.calendar.google.com', + timeMin=now, + timeMax=now_after_one_day, + maxResults=10, singleEvents=True, + orderBy='startTime').execute() + + + events = events_result_autoficher.get('items', []) + events_result_holiday.get('items', []) + + if not events: + return False + + # Prints the start and name of the next 10 events + for event in events: + start = event['start'].get('dateTime', event['start'].get('date')) + end = event['end'].get('dateTime', event['end'].get('date')) + + if datetime.fromisoformat(start).timestamp() <= datetime.now().timestamp() <= datetime.fromisoformat(end).timestamp(): + if event['organizer']['displayName'] == 'autoficher': + return 'Forzado desde autoficher - ' + event['summary'] + + if 'description' in event and ("Cataluña" in event['description'] or 'Día festivo' in event['description']or 'Celebración\n' in event['description']) and not 'Cambio de horario' in event['summary']: + return event['summary'] + except HttpError as error: + print(f'An error occurred: {error}') + return 'Error de llamada a api' + + return 'No se que ha pasado :/' if __name__ == '__main__': af = AutoFicher() diff --git a/requirements.txt b/requirements.txt index 4123103..300d33b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,5 @@ python-telegram-bot pytz +google-api-python-client +google-auth-httplib2 +google-auth-oauthlib \ No newline at end of file