Last active
October 2, 2019 17:52
-
-
Save dikderoy/93b186fcf6d3001e08c14d232097aa31 to your computer and use it in GitHub Desktop.
absence.io python script to put present times automatically
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import logging | |
import os | |
import random | |
import sys | |
from datetime import datetime, timedelta | |
import attr | |
import mohawk | |
import pytz | |
import requests | |
from pytz import tzinfo, utc | |
from requests_hawk import HawkAuth | |
ABS_USER_ID = ABS_KEY_ID = os.getenv('ABS_KEY_ID') | |
ABS_SECRET = os.getenv('ABS_SECRET') | |
if not ABS_KEY_ID or not ABS_SECRET: | |
raise EnvironmentError('you have to provide ABS_KEY_ID and ABS_SECRET env vars') | |
ACTIVE_TZ = pytz.timezone('CET') | |
ABS_TIMESPAN_CREATE_ENDPOINT = "https://app.absence.io/api/v2/timespans/create" | |
logger = logging.getLogger('absence') | |
def basic_logging(level=logging.INFO, timed_logs=True): | |
log_fmt = logging.BASIC_FORMAT | |
if timed_logs: | |
log_fmt = "[%(asctime)s]:" + log_fmt | |
logging.basicConfig(stream=sys.stdout, format=log_fmt, level=level) | |
# noinspection PyProtectedMember | |
logging.info('logger set up with level: %s', logging._levelToName.get(level, level)) | |
def generate_dt(h: int = 10, m: int = 0, deviation: int = 30, base_dt: datetime = None) -> datetime: | |
""" | |
generates a date from current one, which has slight deviation (under 1h interval) based on random | |
""" | |
random.seed() | |
assert deviation < 60, 'deviation cannot be more than an hour (59 minutes)' | |
m_deviation = random.randint(- deviation, + deviation) | |
logger.debug('gen:deviation(%s..%s): %s' % (m - deviation, m + deviation, m_deviation)) | |
# set minutes (always plus as m_dev can be positive and negative number) | |
m_deviation = m + m_deviation | |
# assert minutes validity and adjust | |
if m_deviation > 59: | |
h += 1 | |
m = m_deviation - 59 | |
logger.debug('gen:over59') | |
elif m_deviation < 0: | |
h -= 1 | |
m = 60 - abs(m_deviation) | |
logger.debug('gen:less00') | |
else: | |
m = m_deviation | |
logger.debug('gen:fits59') | |
logger.debug('gen:time: hh:mm | %s:%s' % (h, m)) | |
dt = base_dt or datetime.now() | |
dt = dt.astimezone(ACTIVE_TZ).replace(hour=h, minute=m).astimezone(utc) | |
return dt | |
def format_dt(dt: datetime) -> str: | |
return dt.replace(tzinfo=None).isoformat(sep='T', timespec='milliseconds') + 'Z' | |
def format_tz(tz: tzinfo) -> str: | |
return datetime.now(tz).strftime('%z') | |
@attr.s(auto_attribs=True) | |
class AbsenceClient: | |
_auth: HawkAuth = None | |
def _get_auth(self): | |
if not self._auth: | |
self._auth = HawkAuth(id=ABS_KEY_ID, key=ABS_SECRET, algorithm='sha256') | |
return self._auth | |
def record(self, start: str, end: str) -> bool: | |
url = ABS_TIMESPAN_CREATE_ENDPOINT | |
hawk_auth = self._get_auth() | |
sender = mohawk.Sender( | |
hawk_auth.credentials, | |
url, | |
'POST', | |
always_hash_content=False, | |
) | |
headers = { | |
"Content-Type": "application/json", | |
"Accept": "application/json", | |
"Authorization": sender.request_header, | |
} | |
logger.debug('record:headers:\n%s', json.dumps(headers)) | |
body = { | |
"userId": ABS_USER_ID, | |
"start": start, | |
"end": end, | |
"timezoneName": ACTIVE_TZ.zone, | |
"timezone": format_tz(ACTIVE_TZ), | |
"type": "work" | |
} | |
logger.debug('record:headers:\n%s', body) | |
response = requests.post( | |
url, | |
headers=headers, | |
json=body) | |
logger.debug('record:response:\n%s', response.text) | |
response.raise_for_status() | |
return True | |
def run(client: AbsenceClient, dt: datetime = None): | |
logger.info('main:base_date: %s', dt) | |
start_edt = format_dt(generate_dt(10, 00, deviation=15, base_dt=dt)) | |
logger.info('main:fab:start:%s', start_edt) | |
end_edt = format_dt(generate_dt(19, 00, deviation=15, base_dt=dt)) | |
logger.info('main:fab:end:%s', end_edt) | |
logger.info("!!!recording!!!") | |
assert client.record(start_edt, end_edt) is True | |
logger.info("!!!done!!!") | |
if __name__ == '__main__': | |
basic_logging(level=logging.INFO) | |
dt_from = datetime.fromisoformat("2019-07-06T00:00:00.000+00:00") | |
dt_to = datetime.fromisoformat("2019-09-17T00:00:00.000+00:00") | |
client = AbsenceClient() | |
for dt in (dt_from + timedelta(days=n) for n in range((dt_to - dt_from).days + 1)): | |
if dt.weekday() in {5, 6}: | |
continue | |
logger.info(f'for date: {dt:%Y-%m-%d %a}') | |
run(client, dt) | |
logger.info('__ all done __') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-i https://pypi.org/simple | |
mohawk==1.0.0 | |
pytz>=2019.1 | |
requests-hawk==1.0.0 | |
requests==2.22.0 | |
attrs==19.1.0 |
You forgot "attr" in the requirements :)
fixed =)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You forgot "attr" in the requirements :)