google calendar
Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
config.json
|
||||
googleoauth.json
|
||||
11
README.md
11
README.md
@@ -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.
|
||||
|
||||
110
autoficher.py
110
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))
|
||||
}]
|
||||
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()
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
python-telegram-bot
|
||||
pytz
|
||||
google-api-python-client
|
||||
google-auth-httplib2
|
||||
google-auth-oauthlib
|
||||
Reference in New Issue
Block a user