Final version

This commit is contained in:
Omar Sánchez
2021-10-05 09:59:14 +02:00
parent 7f24b1b5b9
commit d23038c3c5
11 changed files with 191 additions and 45 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

8
.idea/autoficher.iml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,19 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="W191" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<list>
<option value="pika-stubs==0.1.3" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/autoficher.iml" filepath="$PROJECT_DIR$/.idea/autoficher.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

25
README.md Normal file
View File

@@ -0,0 +1,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 <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)
-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

View File

@@ -17,75 +17,108 @@
# Creado: Omar Sánchez 04-05-2019 # Creado: Omar Sánchez 04-05-2019
# Importamos librerias # Importamos librerias
import os
import json import json
import sys from datetime import datetime
from datetime import datetime, timedelta
import pytz
import requests import requests
import urllib.parse
import argparse import argparse
import telegram
# Introducimos los argumentos obligatorios y opcionales # Introducimos los argumentos obligatorios y opcionales
parser = argparse.ArgumentParser(add_help=False) parser = argparse.ArgumentParser(add_help=False)
parser._action_groups.pop() parser._action_groups.pop()
obligatoryArgs = parser.add_argument_group("Argumentos obligatorios") obligatoryArgs = parser.add_argument_group("Argumentos obligatorios")
obligatoryArgs.add_argument('-u', '--user', help="Usuario", required=True) obligatoryArgs.add_argument('-u', '--user', help="Usuario", required=True)
obligatoryArgs.add_argument('-p', '--pin', help="Contraseña", required=True) obligatoryArgs.add_argument('-p', '--pin', help="Contraseña", type=int, required=True)
obligatoryArgs.add_argument('-t', '--type', help="Tipo marcado. 0 = Entrada, 1 = Salida", required=True) obligatoryArgs.add_argument('-t', '--type', help="Tipo marcado. 0 = Entrada, 1 = Salida", type=int)
optionalArgs = parser.add_argument_group("Argumentos opcionales") optionalArgs = parser.add_argument_group("Argumentos opcionales")
optionalArgs.add_argument('-f', '--festive', action="store_false", help="Comprobar festivo") optionalArgs.add_argument('-bt', '--basedtime', help="Hacer check o descheck según la hora del dia", action="store_true")
optionalArgs.add_argument('-h', '--help', action="help", help="Esta ayuda") optionalArgs.add_argument('-h', '--help', action="help", help="Esta ayuda")
args = parser.parse_args() args = parser.parse_args()
class AutoFicher(): class AutoFicher():
# URL de la api # URL de la api
url = "https://timenet.gpisoftware.com/api/v1/cp/" headers = {
# Definimos las variables de tiempo "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
date = datetime.now().strftime("%d/%m/%Y+%H:%M:%S") "tn-v": "3.0.9",
#calendar = (datetime.now() + timedelta(days=3)).strftime("%d/%m/%Y") "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"
calendar = datetime.now().strftime("%d/%m/%Y") }
config = None
token = "" def __init__(self):
self.loadConfig()
def __init__(self, task = ''): def loadConfig(self):
# Iniciamos Sesión y obtenemos el token with open('config.json', 'r') as f:
headers = {'user': args.user, 'pass': args.pin} self.config = json.load(f)
response = requests.get(self.url+'login', headers=headers)
self.token = response.text.replace('"','')
def isFestive(self): def sendReport(self, message):
# Comprobamos si esta habilitado el comprobar festivo (Por defecto es True) bot = telegram.Bot(token=self.config['telegram']['token'])
if args.festive: bot.sendMessage(chat_id=self.config['telegram']['chat_id'], text=str(message))
# Revisamos el dia en el calendario y comprobamos si es festivo o no
headers = {'token': self.token}
response = requests.get(self.url+"calendar?start="+self.calendar+"&end="+self.calendar, headers=headers)
dayType = json.loads(response.text)["DayTypes"][0]["dayMode"]
if dayType == "NO_WORK": def get(self, url, data={}, headers={}):
return True if url != "version":
else: self.url = self.url + "v1/"
return False return requests.get(self.config['api_url']+url, data=data, headers=headers)
else:
return False def post(self, url, data={}, headers={}):
if url != "version":
self.url = self.url + "v1/"
return requests.post(self.config['api_url']+url, data=data, headers=headers)
def updateTime(self):
self.headers["tn-d"] = "\""+datetime.now().astimezone(pytz.UTC).strftime(self.config['time_format'])+"\""
def getVersion(self):
self.updateTime()
return self.get('version', self.headers)
def getInfo(self):
return self.get('check/info', {"guid": args.user})
def sendUpdate(self): def sendUpdate(self):
# Si no es festivo.. self.updateTime()
if not self.isFestive():
# Hacemos la llamada a la api para marcar o desmarcar
print("Dia de curro")
headers = {"Content-type": "application/x-www-form-urlencoded", "token": self.token}
data = {"typ": args.type, "date": urllib.parse.quote(self.date), "geoLatitude": "41.3908992", "geoLongitude": "2.154496", "geoErrors": ""}
response = requests.post(self.url+"checks", data=data, headers=headers) typ = 0
if response.status_code != 200: if args.basedtime and not args.type:
print("Error "+str(response.status_code)+" al realizar el envio: "+ response.request.body) hour = datetime.now().strftime("%H")
hIN = self.config['in_hours']
hOUT = self.config['out_hours']
if hour in hIN:
typ = 0
elif hour in hOUT:
typ = 1
else: else:
print(response.text) print("No se ha fichado ni desfichado ya que estamos en horario laboral, fuerze el estado con el parametro --type <0 = Entrada, 1 = Salida>")
else: else:
print("Hoy no se trabaja") typ = args.type
data = {
"cp": args.user,
"pin": args.pin,
"typ": typ,
"date": self.headers['tn-d'],
"geoLatitude": self.config['geo']['latitude'],
"geoLongitude": self.config['geo']['longitude'],
"geoError": "",
"c": 1,
"geoAccuracy": self.config['geo']['accuracy']
}
response = self.post("check", data, self.headers)
if response.status_code != 200:
self.sendReport('Has fichado correctamente a las ' + str(datetime.strptime(self.headers["tn-d"]).strftime("%H:%M")))
else:
self.sendReport("No se ha podido fichar, la web no ha devuelto 200 OK")
if __name__ == '__main__': if __name__ == '__main__':
AutoFicher().sendUpdate() af = AutoFicher()

28
config.json Normal file
View File

@@ -0,0 +1,28 @@
{
"in_hours": [
"07",
"08",
"09",
"10",
"11",
"15"
],
"out_hours": [
"13",
"14",
"15",
"17",
"18"
],
"api_url": "https://timenet.gpisoftware.com/api/",
"telegram": {
"token": "1502426217:AAEBG7XF6dZqJ6cRmPQk_YykGS5mJFeUEto",
"chat_id": 12878473
},
"geo": {
"latitude": 41.3908992,
"longitude": 2.154496,
"accuracy": 98.31
},
"time_format": "%Y-%m-%dT%H:%M:%SZ"
}

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
python-telegram