Final version
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
8
.idea/autoficher.iml
generated
Normal 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>
|
||||||
19
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
19
.idea/inspectionProfiles/Project_Default.xml
generated
Normal 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>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal 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
4
.idea/misc.xml
generated
Normal 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
8
.idea/modules.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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
25
README.md
Normal 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
|
||||||
119
autoficher.py
119
autoficher.py
@@ -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
28
config.json
Normal 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
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python-telegram
|
||||||
Reference in New Issue
Block a user