diff --git a/timebot.py b/timebot.py index f2c26d8..f3318fb 100644 --- a/timebot.py +++ b/timebot.py @@ -16,9 +16,9 @@ logger = logging.getLogger() logging.basicConfig(level=logging.INFO) -class TimeBot: +class MobatimeApi: def __init__(self, baseurl: str, user: str, password: str = None, ask_for_password: bool = False, - save_session: bool = False): + save_session: bool = False, cookie_store: str = ".kekse"): self.logger = logging.getLogger(self.__class__.__name__) self.baseurl = self._sanitize_baseurl(baseurl) self.user = user @@ -26,6 +26,7 @@ class TimeBot: self._ask_for_password = ask_for_password self._save_session = save_session self._session = None + self._cookie_store = cookie_store self._current_user = None @staticmethod @@ -94,7 +95,7 @@ class TimeBot: :param requests.Session session: the requests session to extract the cookies from """ if self._save_session: - with open(".kekse", "wb") as f: + with open(self._cookie_store, "wb") as f: self.logger.debug("pickling session cookies") pickle.dump(requests.utils.dict_from_cookiejar(session.cookies), f) @@ -105,34 +106,30 @@ class TimeBot: :param requests.Session session: the requests session which will be updated with the loaded cookies """ if self._save_session: - with open(".kekse", "rb") as f: + with open(self._cookie_store, "rb") as f: self.logger.debug("loading pickled cookies") session.cookies.update(requests.utils.cookiejar_from_dict(pickle.load(f))) - def add_entry(self, punch_datetime: datetime.datetime, entry_code: int, note: str = None) -> requests.Response: + @property + def current_user(self): """ - Add mobatime entry. + Returns all user information for the current user. - :param datetime.datetime punch_datetime: datetim object - :param int entry_code: entry type code - :param str note: free text note added to the Mobatime entry - :return: requests response object + :return: all user information as dict """ - punch_date = punch_datetime.strftime(SIMPLE_DATE_FORMAT) - punch_time = punch_datetime.strftime(SIMPLE_TIME_FORMAT) - 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 + 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 list_employees(self): + def get_employees(self): """ List all employees which are obviously in the same team as you. :return: list of employees @@ -141,7 +138,7 @@ class TimeBot: request.raise_for_status() return request.json() - def _get_user_profile_for_current_user(self): + def get_user_profile_for_current_user(self): """ Returns all user information for the current user. @@ -151,24 +148,28 @@ class TimeBot: request.raise_for_status() return request.json() - @property - def current_user(self): + def save_entry(self, punch_datetime: datetime.datetime, entry_code: int, note: str = None) -> requests.Response: """ - 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. + Add mobatime entry. - :return: user id + :param datetime.datetime punch_datetime: datetim object + :param int entry_code: entry type code + :param str note: free text note added to the Mobatime entry + :return: requests response object """ - return self.current_user["employee"]["id"] + punch_date = punch_datetime.strftime(SIMPLE_DATE_FORMAT) + punch_time = punch_datetime.strftime(SIMPLE_TIME_FORMAT) + 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 get_entries(self, entries: int = 10, start_date: datetime.datetime = None, @@ -235,33 +236,68 @@ class TimeBot: request.raise_for_status() return request.json() + +class TimeBot: + def __init__(self, mobatime_api: MobatimeApi): + self.logger = logging.getLogger(self.__class__.__name__) + self.mobatime_api = mobatime_api + def punch_in(self, punch_datetime: datetime.datetime): """ :param datetime.datetime punch_datetime: datetime object :raises: on status code != 2xx """ - self.add_entry(punch_datetime, COMING_ENTRY_CODE_ID, note="da").raise_for_status() + self.mobatime_api.save_entry(punch_datetime, COMING_ENTRY_CODE_ID, note="da").raise_for_status() def punch_out(self, punch_datetime: datetime.datetime): """ :param datetime.datetime punch_datetime: datetime object :raises: on status code != 2xx """ - self.add_entry(punch_datetime, LEAVING_ENTRY_CODE_ID, note="weg").raise_for_status() + self.mobatime_api.save_entry(punch_datetime, LEAVING_ENTRY_CODE_ID, note="weg").raise_for_status() def break_start(self, punch_datetime: datetime.datetime): """ :param datetime.datetime punch_datetime: datetime object :raises: on status code != 2xx """ - self.add_entry(punch_datetime, BREAK_START_ENTRY_CODE_ID, note="pause").raise_for_status() + self.mobatime_api.save_entry(punch_datetime, BREAK_START_ENTRY_CODE_ID, note="pause").raise_for_status() def break_end(self, punch_datetime: datetime.datetime): """ :param datetime.datetime punch_datetime: datetime object :raises: on status code != 2xx """ - self.add_entry(punch_datetime, BREAK_END_ENTRY_CODE_ID, note="pause ende").raise_for_status() + self.mobatime_api.save_entry(punch_datetime, BREAK_END_ENTRY_CODE_ID, note="pause ende").raise_for_status() + + def smart_punch(self, punch_datetime): + last_punch = tb.mobatime_api.get_entries(1, punch_datetime.replace(hour=0, minute=0, second=0, microsecond=0)) + method = None + if not last_punch: + logger.debug("could not detect any time entry for today... punching in") + method = "punch_in" + elif last_punch[0]["entryNumber"] == COMING_ENTRY_CODE_ID: + logger.debug("your last entry was `punch_in`... starting break") + method = "break_start" + elif last_punch[0]["entryNumber"] == BREAK_START_ENTRY_CODE_ID: + logger.debug("your last entry was `break_start`... ending break") + method = "break_end" + elif last_punch[0]["entryNumber"] == BREAK_END_ENTRY_CODE_ID: + logger.debug("your last entry was `break_end`... punching out") + method = "punch_out" + elif last_punch[0]["entryNumber"] == LEAVING_ENTRY_CODE_ID: + logger.error("your last entry was `punch_out`... punching in again with this command is not supported") + sys.exit(1) + if method is None: + logger.error("hit an unknown situation... detection failed; run with `-v` for more info") + logger.debug(f"last entry was: {last_punch}") + exit(1) + logger.info("running `{}` with date `{}` and time `{}`".format( + method, + punch_datetime.strftime(SIMPLE_DATE_FORMAT), + punch_datetime.strftime(SIMPLE_TIME_FORMAT), + )) + getattr(self, method)(punch_datetime) if __name__ == '__main__': @@ -313,8 +349,9 @@ if __name__ == '__main__': config = configparser.ConfigParser() config.read(args.c) - tb = TimeBot(baseurl=config["general"]["baseurl"], user=args.u, password=args.p, ask_for_password=True, - save_session=args.save_cookies) + ma = MobatimeApi(baseurl=config["general"]["baseurl"], user=args.u, password=args.p, ask_for_password=True, + save_session=args.save_cookies) + tb = TimeBot(mobatime_api=ma) if args.subparser_name == "punch": if args.s == "now": punch_datetime = datetime.datetime.now() @@ -331,33 +368,7 @@ if __name__ == '__main__': punch_datetime = datetime.datetime.now() else: punch_datetime = datetime.datetime.strptime(args.s, SIMPLE_DATETIME_FORMAT) - last_punch = tb.get_entries(1, punch_datetime.replace(hour=0, minute=0, second=0, microsecond=0)) - method = None - if not last_punch: - logger.debug("could not detect any time entry for today... punching in") - method = "punch_in" - elif last_punch[0]["entryNumber"] == COMING_ENTRY_CODE_ID: - logger.debug("your last entry was `punch_in`... starting break") - method = "break_start" - elif last_punch[0]["entryNumber"] == BREAK_START_ENTRY_CODE_ID: - logger.debug("your last entry was `break_start`... ending break") - method = "break_end" - elif last_punch[0]["entryNumber"] == BREAK_END_ENTRY_CODE_ID: - logger.debug("your last entry was `break_end`... punching out") - method = "punch_out" - elif last_punch[0]["entryNumber"] == LEAVING_ENTRY_CODE_ID: - logger.error("your last entry was `punch_out`... punching in again with this command is not supported") - sys.exit(1) - if method is None: - logger.error("hit an unknown situation... detection failed; run with `-v` for more info") - logger.debug(f"last entry was: {last_punch}") - exit(1) - logger.info("running `{}` with date `{}` and time `{}`".format( - method, - punch_datetime.strftime(SIMPLE_DATE_FORMAT), - punch_datetime.strftime(SIMPLE_TIME_FORMAT), - )) - getattr(tb, method)(punch_datetime) + tb.smart_punch(punch_datetime) elif args.subparser_name == "list-entries": end_date = None if args.end_date: @@ -365,13 +376,13 @@ if __name__ == '__main__': start_date = None if args.start_date: start_date = datetime.datetime.strptime(args.start_date, SIMPLE_DATETIME_FORMAT) - data = tb.get_entries(entries=args.items, start_date=start_date, end_date=end_date) + data = tb.mobatime_api.get_entries(entries=args.items, start_date=start_date, end_date=end_date) data.reverse() for i in data: print("Entry: {} - DateTime: {} - Note: {}".format(i["entryName"], i["dateTime"], i["note"])) elif args.subparser_name == "status": - tracking_data = tb.get_tracking_data() - account_info = tb.get_account_information() + tracking_data = tb.mobatime_api.get_tracking_data() + account_info = tb.mobatime_api.get_account_information() print("Tracking Info:") print(f" Current State: {tracking_data['actualState']}") print(f" Last Booking: {tracking_data['lastBooking']}")