google calendar

Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
Omar Sánchez Pizarro
2022-10-25 13:10:55 +02:00
parent 321f88f16a
commit 73dc43a193
4 changed files with 108 additions and 25 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
config.json
googleoauth.json

View File

@@ -2,20 +2,16 @@ 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 <user> -p <pin> [-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
@@ -23,3 +19,8 @@ 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
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.

View File

@@ -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))
}]
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()

View File

@@ -1,2 +1,5 @@
python-telegram-bot
pytz
google-api-python-client
google-auth-httplib2
google-auth-oauthlib