Compare commits
3 Commits
5ed5a73950
...
db6d7ac640
Author | SHA1 | Date | |
---|---|---|---|
db6d7ac640 | |||
69d471a859 | |||
4fcf972e17 |
@ -1,16 +1,21 @@
|
||||
#!/usr/bin/env python3.7
|
||||
import os
|
||||
import csv
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
import click
|
||||
import requests
|
||||
from peewee import fn, JOIN
|
||||
from textual.logging import TextualHandler
|
||||
|
||||
from xdg.BaseDirectory import xdg_config_home
|
||||
|
||||
|
||||
from .db import (
|
||||
KimaiTag,
|
||||
db,
|
||||
@ -22,19 +27,31 @@ from .db import (
|
||||
KimaiActivity,
|
||||
HamsterActivityKimaiMapping,
|
||||
HamsterFactKimaiImport,
|
||||
HamsterFactTag,
|
||||
)
|
||||
from .kimaiapi import KimaiAPI, Timesheet
|
||||
from .sync import sync
|
||||
|
||||
CONFIG_FILE = Path(xdg_config_home) / "hamstertools.toml"
|
||||
|
||||
HAMSTER_DIR = Path.home() / ".local/share/hamster"
|
||||
HAMSTER_FILE = HAMSTER_DIR / "hamster.db"
|
||||
|
||||
db.init(HAMSTER_FILE)
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.group(context_settings={"auto_envvar_prefix": "HAMSTERTOOL"})
|
||||
@click.option("-d", "--debug", is_flag=True)
|
||||
def cli(debug):
|
||||
@click.option("--config", default=CONFIG_FILE, type=click.Path())
|
||||
@click.option("--kimai-api-url", envvar="KIMAI_API_URL")
|
||||
@click.option("--kimai-username", envvar="KIMAI_USERNAME")
|
||||
@click.option("--kimai-api-key", envvar="KIMAI_API_KEY")
|
||||
@click.pass_context
|
||||
def cli(ctx, config, debug, kimai_api_url=None, kimai_username=None, kimai_api_key=None):
|
||||
file_config = {}
|
||||
if os.path.exists(config):
|
||||
with open(config, "rb") as f:
|
||||
file_config = tomllib.load(f)
|
||||
if debug:
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
@ -47,6 +64,12 @@ def cli(debug):
|
||||
requests_log.setLevel(logging.DEBUG)
|
||||
requests_log.propagate = True
|
||||
|
||||
ctx.obj = KimaiAPI(
|
||||
kimai_username if kimai_username is not None else file_config.get("kimai_username"),
|
||||
kimai_api_key if kimai_api_key is not None else file_config.get("kimai_api_key"),
|
||||
kimai_api_url if kimai_api_url is not None else file_config.get("kimai_api_url"),
|
||||
)
|
||||
|
||||
|
||||
@cli.group()
|
||||
def categories():
|
||||
@ -355,7 +378,6 @@ def _get_kimai_mapping_file(path, category_search=None):
|
||||
multiple=True,
|
||||
)
|
||||
@click.argument("username")
|
||||
@click.argument("api_key", envvar="KIMAI_API_KEY")
|
||||
@click.option("--just-errors", "just_errors", is_flag=True, help="Only display errors")
|
||||
@click.option("--ignore-activities", is_flag=True, help="Ignore missing activities")
|
||||
def check(username, api_key, just_errors, ignore_activities, mapping_path=None):
|
||||
@ -644,7 +666,7 @@ def _csv(
|
||||
@click.argument("after")
|
||||
@click.argument("before")
|
||||
def _import(search, after, before):
|
||||
api = KimaiAPI()
|
||||
api = KimaiAPI(username=KIMAI_USERNAME, api_key=KIMAI_API_KEY)
|
||||
|
||||
SEARCH = "auto"
|
||||
|
||||
@ -652,6 +674,8 @@ def _import(search, after, before):
|
||||
HamsterFact.select(HamsterFact, HamsterActivity, HamsterCategory)
|
||||
.join(HamsterActivity, JOIN.LEFT_OUTER)
|
||||
.join(HamsterCategory, JOIN.LEFT_OUTER)
|
||||
.switch(HamsterFact)
|
||||
.join(HamsterFactTag, JOIN.LEFT_OUTER)
|
||||
.where(
|
||||
(HamsterFact.start_time > datetime.strptime(after, "%Y-%m-%d"))
|
||||
& (HamsterFact.start_time < datetime.strptime(before, "%Y-%m-%d"))
|
||||
@ -729,9 +753,6 @@ def _import(search, after, before):
|
||||
if r.get("code", 200) != 200:
|
||||
print(r)
|
||||
print(f"{f.id} ({f.activity.category.name} » {f.activity.name})")
|
||||
from pdb import set_trace
|
||||
|
||||
set_trace()
|
||||
|
||||
else:
|
||||
HamsterFactKimaiImport.create(hamster_fact=f, kimai_id=r["id"]).save()
|
||||
@ -763,8 +784,11 @@ def reset():
|
||||
|
||||
|
||||
@db_.command("sync")
|
||||
def kimai_db_sync():
|
||||
sync()
|
||||
@click.pass_obj
|
||||
def kimai_db_sync(api):
|
||||
sync(
|
||||
api
|
||||
)
|
||||
|
||||
|
||||
@db_.command()
|
||||
@ -805,10 +829,13 @@ def mapping2db(mapping_path=None, global_=False):
|
||||
|
||||
|
||||
@cli.command()
|
||||
def app():
|
||||
@click.pass_obj
|
||||
def app(kimai_api):
|
||||
from .app import HamsterToolsApp
|
||||
|
||||
app = HamsterToolsApp()
|
||||
app = HamsterToolsApp(
|
||||
kimai_api
|
||||
)
|
||||
app.run()
|
||||
|
||||
|
||||
|
@ -16,25 +16,20 @@ class HamsterToolsApp(App):
|
||||
("q", "quit", "Quit"),
|
||||
]
|
||||
|
||||
api_ = None
|
||||
|
||||
@property
|
||||
def api(self) -> KimaiAPI:
|
||||
if self.api_ is None:
|
||||
self.api_ = KimaiAPI()
|
||||
return self.api_
|
||||
|
||||
def __init__(self):
|
||||
self.MODES = {
|
||||
"hamster": HamsterScreen(),
|
||||
"kimai": KimaiScreen(),
|
||||
}
|
||||
def __init__(self, kimai_api=None):
|
||||
self.add_mode("hamster", HamsterScreen())
|
||||
self.add_mode("kimai", KimaiScreen())
|
||||
# self.mode MODES = {
|
||||
# "hamster": HamsterScreen(),
|
||||
# "kimai": KimaiScreen(),
|
||||
# }
|
||||
self.api = kimai_api
|
||||
|
||||
super().__init__()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.switch_mode("hamster")
|
||||
|
||||
def action_quit(self) -> None:
|
||||
async def action_quit(self) -> None:
|
||||
db.close()
|
||||
self.exit()
|
||||
|
@ -1,6 +1,7 @@
|
||||
from datetime import datetime
|
||||
|
||||
from peewee import (
|
||||
CompositeKey,
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
CharField,
|
||||
@ -32,6 +33,14 @@ class HamsterActivity(Model):
|
||||
table_name = "activities"
|
||||
|
||||
|
||||
class HamsterTag(Model):
|
||||
name = CharField()
|
||||
|
||||
class Meta:
|
||||
database = db
|
||||
table_name = "tags"
|
||||
|
||||
|
||||
class HamsterFact(Model):
|
||||
activity = ForeignKeyField(HamsterActivity, backref="facts")
|
||||
start_time = DateTimeField()
|
||||
@ -43,15 +52,6 @@ class HamsterFact(Model):
|
||||
table_name = "facts"
|
||||
|
||||
|
||||
class HamsterTag(Model):
|
||||
name = CharField()
|
||||
|
||||
class Meta:
|
||||
database = db
|
||||
table_name = "tags"
|
||||
|
||||
|
||||
|
||||
class HamsterFactTag(Model):
|
||||
fact = ForeignKeyField(HamsterFact, backref="tags")
|
||||
tag = ForeignKeyField(HamsterTag, backref="facts")
|
||||
|
@ -1,8 +1,6 @@
|
||||
from datetime import datetime
|
||||
import pdb
|
||||
import requests
|
||||
import requests_cache
|
||||
import os
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
@ -12,16 +10,12 @@ class NotFound(Exception):
|
||||
|
||||
|
||||
class KimaiAPI(object):
|
||||
# temporary hardcoded config
|
||||
KIMAI_API_URL = "https://kimai.autonomic.zone/api"
|
||||
# KIMAI_API_URL = "https://kimaitest.autonomic.zone/api"
|
||||
|
||||
KIMAI_USERNAME = "3wordchant"
|
||||
KIMAI_API_KEY = os.environ["KIMAI_API_KEY"]
|
||||
|
||||
auth_headers = {"X-AUTH-USER": KIMAI_USERNAME, "X-AUTH-TOKEN": KIMAI_API_KEY}
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, username=None, api_key=None, api_url=None):
|
||||
self.auth_headers = {"X-AUTH-USER": username, "X-AUTH-TOKEN": api_key}
|
||||
self.kimai_api_url = api_url
|
||||
# NOTE: Uncomment the following line to enable requests_cache, which can make development a *lot* faster
|
||||
# TODO: Add a config option or something for this
|
||||
# import requests_cache
|
||||
# requests_cache.install_cache("kimai", backend="sqlite", expire_after=1800)
|
||||
self.customers_json = self.get("customers", {"visible": 3})
|
||||
self.projects_json = self.get("projects", {"visible": 3, "ignoreDates": 1})
|
||||
@ -31,7 +25,7 @@ class KimaiAPI(object):
|
||||
|
||||
def get(self, endpoint, params=None):
|
||||
result = requests.get(
|
||||
f"{self.KIMAI_API_URL}/{endpoint}", params=params, headers=self.auth_headers
|
||||
f"{self.kimai_api_url}/{endpoint}", params=params, headers=self.auth_headers
|
||||
).json()
|
||||
try:
|
||||
if result["code"] != 200:
|
||||
@ -42,7 +36,7 @@ class KimaiAPI(object):
|
||||
|
||||
def post(self, endpoint, data):
|
||||
return requests.post(
|
||||
f"{self.KIMAI_API_URL}/{endpoint}", json=data, headers=self.auth_headers
|
||||
f"{self.kimai_api_url}/{endpoint}", json=data, headers=self.auth_headers
|
||||
)
|
||||
|
||||
|
||||
|
@ -14,9 +14,7 @@ from .db import (
|
||||
)
|
||||
|
||||
|
||||
def sync() -> None:
|
||||
api = KimaiAPI()
|
||||
|
||||
def sync(api) -> None:
|
||||
KimaiCustomer.delete().execute()
|
||||
KimaiProject.delete().execute()
|
||||
KimaiActivity.delete().execute()
|
||||
|
@ -4,3 +4,4 @@ requests-cache==1.1.1
|
||||
textual==0.44.1
|
||||
textual-autocomplete==2.1.0b0
|
||||
textual-dev==1.2.1
|
||||
xdg==6.0.0
|
||||
|
Reference in New Issue
Block a user