You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
6.8 KiB
192 lines
6.8 KiB
import argparse
|
|
import configparser
|
|
import getpass
|
|
import logging
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
import requests as requests
|
|
|
|
from constants import COMING_ENTRY_CODE_ID, LEAVING_ENTRY_CODE_ID, PUNCH_COMMANDS, BREAK_START_ENTRY_CODE_ID, \
|
|
BREAK_END_ENTRY_CODE_ID
|
|
|
|
logger = logging.getLogger()
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
class TimeBot:
|
|
def __init__(self, baseurl: str, user: str, password: str):
|
|
self.logger = logging.getLogger(self.__class__.__name__)
|
|
self.baseurl = baseurl
|
|
self.user = user
|
|
self.password = password
|
|
self._session = None
|
|
self._current_user = 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.get_current_user_id(),
|
|
}
|
|
if note:
|
|
entry_data["note"] = note
|
|
request = self.session.post(self.baseurl + "Entry/SaveEntry", data=entry_data)
|
|
return request
|
|
|
|
def list_employees(self):
|
|
"""
|
|
List all employees which are obviously in the same team as you.
|
|
:return: list of employees
|
|
"""
|
|
request = self.session.get(self.baseurl + "Employee/GetEmployees")
|
|
request.raise_for_status()
|
|
return request.json()
|
|
|
|
def _get_user_profile_for_current_user(self):
|
|
"""
|
|
Returns all user information for the current user.
|
|
|
|
:return: all user information as dict
|
|
"""
|
|
request = self.session.get(self.baseurl + "Employee/GetUserProfileForCurrentUser")
|
|
request.raise_for_status()
|
|
return request.json()
|
|
|
|
@property
|
|
def current_user(self):
|
|
"""
|
|
Returns all user information for the current user.
|
|
|
|
:return: all user information as dict
|
|
"""
|
|
if self._current_user is None:
|
|
self._current_user = self._get_user_profile_for_current_user()
|
|
return self._current_user
|
|
|
|
def get_current_user_id(self):
|
|
"""
|
|
Get the current users id.
|
|
|
|
:return: user id
|
|
"""
|
|
return self.current_user["employee"]["id"]
|
|
|
|
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()
|
|
|
|
def break_start(self, punch_date: str, punch_time: str):
|
|
"""
|
|
:param str punch_date: date string in format: ``DD.MM.YYYY``
|
|
:param str punch_time: time string in format: ``hh:mm``
|
|
:raises: on status code != 2xx
|
|
"""
|
|
self.add_entry(punch_date, punch_time, BREAK_START_ENTRY_CODE_ID, note="pause").raise_for_status()
|
|
|
|
def break_end(self, punch_date: str, punch_time: str):
|
|
"""
|
|
:param str punch_date: date string in format: ``DD.MM.YYYY``
|
|
:param str punch_time: time string in format: ``hh:mm``
|
|
:raises: on status code != 2xx
|
|
"""
|
|
self.add_entry(punch_date, punch_time, BREAK_END_ENTRY_CODE_ID, note="pause ende").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("-p", help="mobatime login user password", default=None)
|
|
parser.add_argument("-c", help="config file", default="timebot.ini")
|
|
subparsers = parser.add_subparsers(help='sub-command help', dest='subparser_name')
|
|
|
|
parser_punch = subparsers.add_parser("punch",
|
|
help="use this command to punch in, punch out, or create break entries")
|
|
parser_punch.add_argument("-t",
|
|
help="type of time entry; this can be `punch_in`, `punch_out`, `break_start`, `break_end`",
|
|
default="punch_in",
|
|
choices=PUNCH_COMMANDS)
|
|
parser_punch.add_argument("-s", help="timestamp in format `DD.MM.YYYY_hh:mm` or `now`", default="now")
|
|
|
|
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)
|
|
if args.subparser_name == "punch":
|
|
if args.s == "now":
|
|
now = datetime.now()
|
|
punch_date = now.strftime("%d.%m.%Y")
|
|
punch_time = now.strftime("%H:%M")
|
|
else:
|
|
punch_date = args.s.split("_")[0]
|
|
punch_time = args.s.split("_")[1]
|
|
logger.info("running `{}` with date `{}` and time `{}`".format(args.t, punch_date, punch_time))
|
|
getattr(tb, args.t)(punch_date, punch_time)
|
|
else:
|
|
logger.error("Noting done... dunno what you want!")
|
|
sys.exit(1)
|
|
|
|
sys.exit(0)
|
|
|