From 68998be917312ee994a7c492a8bc67f688183ea7 Mon Sep 17 00:00:00 2001 From: 3wc <3wc@doesthisthing.work> Date: Thu, 7 Aug 2025 14:28:12 +0100 Subject: [PATCH] Remove ancient `kimai csv` command, add Clockify mapping2db --- hamstertools/__init__.py | 188 ++++++++------------------------------- hamstertools/clockify.py | 1 - hamstertools/db.py | 1 + 3 files changed, 36 insertions(+), 154 deletions(-) diff --git a/hamstertools/__init__.py b/hamstertools/__init__.py index 1a5d2db..d145cd7 100755 --- a/hamstertools/__init__.py +++ b/hamstertools/__init__.py @@ -513,149 +513,6 @@ def check(username, api_key, just_errors, ignore_activities, mapping_path=None): found_activities.append(activity_str) -@kimai.command("csv") -@click.option( - "--mapping-path", - help="Mapping file (default ~/.local/share/hamster/mapping.kimai.csv)", - multiple=True, -) -@click.option("--output", help="Output file (default kimai.csv)") -@click.option("--category-search", help="Category search string") -@click.option("--after", help="Only show time entries after this date") -@click.option("--show-missing", help="Just report on the missing entries", is_flag=True) -@click.argument("username") -def _csv( - username, - mapping_path=None, - output=None, - category_search=None, - after=None, - show_missing=False, -): - """ - Export time tracking data in Kimai format - """ - - if mapping_path is None: - mapping_path = HAMSTER_DIR / "mapping.kimai.csv" - - if output is None: - timestamp = datetime.now().strftime("%F") - output = f"kimai_{timestamp}.csv" - - if isinstance(mapping_path, tuple): - mapping_files = [] - for mapping_path_item in mapping_path: - mapping_file = _get_kimai_mapping_file(mapping_path_item, category_search) - next(mapping_file) - mapping_files.append(mapping_file) - mapping_reader = csv.reader(chain(*mapping_files)) - else: - mapping_file = _get_kimai_mapping_file(mapping_path, category_search) - next(mapping_file) - mapping_reader = csv.reader(mapping_file) - - mapping = { - "{0}:{1}".format(row[0], row[1]): [row[2], row[3], row[4], row[5]] - for row in mapping_reader - } - - if isinstance(mapping_path, tuple): - for mapping_file in mapping_files: - mapping_file.close() - else: - mapping_file.close() - - output_file = open(output, "w") - output_writer = csv.writer(output_file) - - facts = ( - HamsterFact.select(HamsterFact, HamsterActivity, HamsterCategory) - .join(HamsterActivity) - .join(HamsterCategory, JOIN.LEFT_OUTER) - ) - - - - if category_search is not None: - facts = facts.where(HamsterCategory.name.contains(category_search)) - - if after is not None: - facts = facts.where(HamsterFact.start_time >= after) - - if not show_missing: - output_writer.writerow( - [ - "Date", - "From", - "To", - "Duration", - "Rate", - "User", - "Customer", - "Project", - "Activity", - "Description", - "Exported", - "Tags", - "HourlyRate", - "FixedRate", - "InternalRate", - ] - ) - - for fact in facts: - k = f"{fact.activity.category.name}:{fact.activity.name}" - try: - mapping_ = mapping[k] - except KeyError: - if show_missing: - output_writer.writerow( - [fact.activity.category.name, fact.activity.name] - ) - click.secho("Can't find mapping for '{0}', skipping".format(k), fg="yellow") - continue - - if show_missing: - continue - - if fact.start_time is None or fact.end_time is None: - click.secho( - f"Missing duration data '{fact.start_time}-{fact.end_time}', skipping", - fg="yellow", - ) - continue - - if len(mapping_) < 5: - mapping_.append(None) - - date_start, date_end = ( - datetime.strptime(fact.start_time.split(".")[0], "%Y-%m-%d %H:%M:%S"), - datetime.strptime(fact.end_time.split(".")[0], "%Y-%m-%d %H:%M:%S"), - ) - duration = (date_start - date_end).seconds / 3600 - - output_writer.writerow( - [ - date_start.strftime("%Y-%m-%d"), - date_start.strftime("%H:%M"), - "", # To (time) - duration, - "", # Rate - username, - mapping_[0], - mapping_[1], - mapping_[2], - fact.description or mapping_[4] or "", - "0", # Exported - mapping_[3], - "", # Hourly rate - "", # Fixed rate - ] - ) - - output_file.close() - @kimai.command("import") @click.argument("search") @@ -788,7 +645,7 @@ def kimai_db_sync(ctx): ) -@kimai_db.command() +@kimai_db.command("mapping2db") @click.option( "-g", "--global", @@ -797,7 +654,7 @@ def kimai_db_sync(ctx): is_flag=True, ) @click.option("--mapping-path", help="Mapping file") -def mapping2db(mapping_path=None, global_=False): +def kimai_mapping2db(mapping_path=None, global_=False): mapping_file = _get_kimai_mapping_file(mapping_path, None) next(mapping_file) mapping_reader = csv.reader(mapping_file) @@ -825,6 +682,15 @@ def mapping2db(mapping_path=None, global_=False): ) +@kimai.command("app") +@click.pass_context +def kimai_app(ctx): + from .app import HamsterToolsAppKimai + + app = HamsterToolsAppKimai(ctx.obj['kimai']) + app.run() + + @cli.group() @click.option("--api-key", envvar="CLOCKIFY_API_KEY", help="Clockify API key") @click.option("--workspace-id", envvar="CLOCKIFY_WORKSPACE_ID", help="Clockify workspace ID") @@ -860,6 +726,30 @@ def clockify_db_init(): ] ) +@clockify_db.command("reset") +def clockify_db_reset(): + HamsterClockifyMapping.delete().execute() + +@clockify_db.command("mapping2db") +@click.argument("mapping-path") +def clockify_mapping2db(mapping_path): + mapping_file = open(mapping_path, "r") + next(mapping_file) + mapping_reader = csv.reader(mapping_file) + + for row in mapping_reader: + hamster_category = HamsterCategory.get(name=row[0]) + hamster_activity = HamsterActivity.get( + name=row[1], category_id=hamster_category.id + ) + clockify_project = ClockifyProject.get(clockify_id=row[2]) + + HamsterClockifyMapping.create( + hamster_activity=hamster_activity, + clockify_project=clockify_project, + clockify_description=row[3], + ) + @clockify.command("app") @click.pass_context def clockify_app(ctx): @@ -868,14 +758,6 @@ def clockify_app(ctx): app = HamsterToolsAppClockify(ctx.obj['clockify']) app.run() -@kimai.command("app") -@click.pass_context -def kimai_app(ctx): - from .app import HamsterToolsAppKimai - - app = HamsterToolsAppKimai(ctx.obj['kimai']) - app.run() - @cli.command() def app(): diff --git a/hamstertools/clockify.py b/hamstertools/clockify.py index 7836620..cf69936 100644 --- a/hamstertools/clockify.py +++ b/hamstertools/clockify.py @@ -46,7 +46,6 @@ def sync_projects(api, db): for project in projects ] ) - breakpoint() query.execute() return len(projects) diff --git a/hamstertools/db.py b/hamstertools/db.py index 4b3f3e3..4658830 100644 --- a/hamstertools/db.py +++ b/hamstertools/db.py @@ -136,6 +136,7 @@ class ClockifyProject(Model): class HamsterClockifyMapping(Model): hamster_activity = ForeignKeyField(HamsterActivity, backref="clockify_mappings") clockify_project = ForeignKeyField(ClockifyProject, backref="mappings") + clockify_description = CharField() created_at = DateTimeField(default=datetime.now) class Meta: