commit 0eb314efcafec9407cd726a1261c3632320a01ff Author: Maximilian Zettler Date: Tue Nov 23 09:40:40 2021 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af20338 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv/ +timebot.ini +__pycache__/ +.idea/ diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..2ea2e8d --- /dev/null +++ b/constants.py @@ -0,0 +1,4 @@ +COMING_ENTRY_CODE_ID = 16 +LEAVING_ENTRY_CODE_ID = 32 +BREAK_START_ENTRY_CODE_ID = 48 +BREAK_END_ENTRY_CODE_ID = 64 diff --git a/timebot.ini.ex b/timebot.ini.ex new file mode 100644 index 0000000..0aeba59 --- /dev/null +++ b/timebot.ini.ex @@ -0,0 +1,2 @@ +[general] +baseurl=https://host/mobatime/ \ No newline at end of file diff --git a/timebot.py b/timebot.py new file mode 100644 index 0000000..5d5eac9 --- /dev/null +++ b/timebot.py @@ -0,0 +1,118 @@ +import argparse +import configparser +import getpass +import logging + +import requests as requests + +from constants import COMING_ENTRY_CODE_ID, LEAVING_ENTRY_CODE_ID + +logger = logging.getLogger() +logging.basicConfig(level=logging.INFO) + + +class TimeBot: + def __init__(self, baseurl: str, user: str, password: str, employee_id: str): + self.logger = logging.getLogger(self.__class__.__name__) + self.baseurl = baseurl + self.user = user + self.password = password + self.employee_id = employee_id + self._session = None + + @property + def session(self): + """ + Return requests session object and auto login if necessary. + + :return: requests session + :raises on any http error + """ + if self._session is None: + self._session = requests.Session() + request = self._session.get(self.baseurl + "Employee/GetEmployeeList") + if 400 <= request.status_code < 500: + self._login(self._session) + else: + request.raise_for_status() + return self._session + + def _login(self, session): + """ + Obtain session cookie. + + :raises: on status code != 2xx + """ + login_data = { + "username": self.user, + "password": self.password, + } + request = session.post(self.baseurl + "Account/LogOn", data=login_data) + request.raise_for_status() + + def add_entry(self, punch_date: str, punch_time: str, entry_code: int, note: str = None) -> requests.Response: + """ + Add mobatime entry. + + :param str punch_date: date string in format: ``DD.MM.YYYY`` + :param str punch_time: time string in format: ``hh:mm`` + :param int entry_code: entry type code + :param str note: free text note added to the Mobatime entry + :return: requests response object + """ + entry_data = { + "periode0Date": punch_date, + "periode0Time": punch_time, + "selectedEntryCode": entry_code, + "selectedPeriodType": 0, + "employeeId": self.employee_id, + } + if note: + entry_data["note"] = note + request = self.session.post(self.baseurl + "Entry/SaveEntry", data=entry_data) + return request + + def list_employees(self): + request = self.session.get(self.baseurl + "Employee/GetEmployees") + request.raise_for_status() + return request.json() + + def punch_in(self, punch_in_date: str, punch_in_time: str): + """ + :param str punch_in_date: date string in format: ``DD.MM.YYYY`` + :param str punch_in_time: time string in format: ``hh:mm`` + :raises: on status code != 2xx + """ + self.add_entry(punch_in_date, punch_in_time, COMING_ENTRY_CODE_ID, note="da").raise_for_status() + + def punch_out(self, punch_out_date: str, punch_out_time: str): + """ + :param str punch_out_date: date string in format: ``DD.MM.YYYY`` + :param str punch_out_time: time string in format: ``hh:mm`` + :raises: on status code != 2xx + """ + self.add_entry(punch_out_date, punch_out_time, LEAVING_ENTRY_CODE_ID, note="weg").raise_for_status() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-v", help="enable debug logging", action="store_true") + parser.add_argument("-u", help="mobatime login user", required=True) + parser.add_argument("-i", help="mobatime employee id", required=True) + parser.add_argument("-p", help="mobatime login user password", default=None) + parser.add_argument("-c", help="config file", default="timebot.ini") + args = parser.parse_args() + + if args.v: + logger.setLevel(logging.DEBUG) + + password = args.p + if password is None: + password = getpass.getpass("Enter your password: ") + + config = configparser.ConfigParser() + config.read(args.c) + + tb = TimeBot(baseurl=config["general"]["baseurl"], user=args.u, password=password, employee_id=args.i) + tb.punch_in("23.11.2021", "09:00") + tb.punch_out("23.11.2021", "18:00")