#!/usr/bin/env python3.7 import sqlite3 import click from pathlib import Path HAMSTER_FILE = Path.home() / '.local/share/hamster-applet/hamster.db' conn = sqlite3.connect(HAMSTER_FILE) c = conn.cursor() def get_categories(ids=None, search=None): sql = ''' SELECT id, name FROM categories ''' args = [] if ids is not None: sql = sql + 'WHERE id IN ({seq})'.format( seq=','.join(['?'] * len(ids)) ) args = args + list(ids) if search is not None: sql = sql + " WHERE name LIKE ?" search = '%{0}%'.format(search) args.append(search) results = c.execute(sql, args) results = c.fetchall() return results def get_activities(ids=None, search=None): sql = ''' SELECT activities.id, activities.name, categories.name, categories.id FROM activities LEFT JOIN categories ON activities.category_id = categories.id ''' args = [] if ids is not None: sql = sql + 'WHERE activities.id IN ({seq})'.format( seq=','.join(['?'] * len(ids)) ) args = args + list(ids) if search is not None: sql = sql + " WHERE activities.name LIKE ?" search = '%{0}%'.format(search) args.append(search) results = c.execute(sql, args) results = c.fetchall() return results @click.group() def cli(): pass @cli.group() def categories(): pass @categories.command('list') @click.option('--search', help='Search string') def list_categories(search): """ List / search categories """ results = get_categories(search=search) for r in results: click.echo('@{0[0]}: {0[1]}'.format(r)) @categories.command('delete') @click.argument('ids', nargs=-1) def delete_categories(ids): """ Delete categories specified by IDS """ click.secho('Deleting:', fg='red') results = get_categories(ids) for r in results: sql = 'SELECT COUNT(id) FROM activities WHERE category_id = ?' count = c.execute(sql, (r[0],)).fetchone()[0] click.echo('@{0[0]}: {0[1]} ({1} activities)'.format(r, count)) click.confirm('Do you want to continue?', abort=True) sql = 'DELETE FROM categories ' sql = sql + 'WHERE id IN ({seq})'.format( seq=','.join(['?'] * len(ids)) ) c.execute(sql, ids) conn.commit() click.secho('Deleted {0} categories'.format(len(ids)), fg='green') @categories.command('activities') @click.argument('ids', nargs=-1) def list_category_activities(ids): """ Show activities for categories specified by IDS """ sql = ''' SELECT activities.id, activities.name, categories.name FROM activities LEFT JOIN categories ON activities.category_id = categories.id WHERE categories.id IN ({seq}) '''.format( seq=','.join(['?'] * len(ids)) ) results = c.execute(sql, ids) for r in results: click.echo('@{0[0]}: {0[2]} » {0[1]}'.format(r)) @cli.group() def activities(): pass @activities.command('list') @click.option('--search', help='Search string') def list_activities(search): """ List / search activities """ results = get_activities(search=search) for r in results: click.echo('@{0[3]}: {0[2]} » {0[0]}: {0[1]}'.format(r)) @activities.command('delete') @click.argument('ids', nargs=-1) def delete_activities(ids): """ Delete activities specified by IDS """ results = get_activities(ids) click.secho('Deleting:', fg='red') for r in results: sql = "SELECT COUNT(id) FROM facts WHERE activity_id = ?" count = c.execute(sql, (r[0],)).fetchone()[0] click.echo('@{0[0]}: {0[2]} » {0[1]} ({1} facts)'.format(r, count)) click.confirm('Do you want to continue?', abort=True) sql = 'DELETE FROM activities ' sql = sql + 'WHERE id IN ({seq})'.format( seq=','.join(['?'] * len(ids)) ) c.execute(sql, ids) conn.commit() click.secho('Deleted {0} activities'.format(len(ids)), fg='green') @activities.command() @click.argument('category_id') @click.argument('ids', nargs=-1) def move(category_id, ids): """ Move activities to another category """ category = get_categories((category_id,))[0] results = get_activities(ids) click.secho('Moving to "@{0[0]}: {0[1]}":'.format(category), fg='green') for r in results: click.secho('@{0[3]}: {0[2]} » @{0[0]}: {0[1]}'.format(r), fg='blue') click.confirm('Do you want to continue?', abort=True) sql = ''' UPDATE activities SET category_id = ? ''' sql = sql + 'WHERE id IN ({seq})'.format( seq=','.join(['?'] * len(ids)) ) c.execute(sql, (category[0], *ids)) conn.commit() click.secho('Moved {0} activities'.format(len(ids)), fg='green') @activities.command() @click.argument('ids', nargs=-1) def list_facts(ids): """ Show facts for activities """ results = get_activities(ids) for r in results: click.secho( '@{0[0]}: {0[1]}'.format(r), fg='green' ) sql = ''' SELECT start_time, activities.name FROM facts LEFT JOIN activities ON facts.activity_id = activities.id WHERE activities.id = ? ''' results = c.execute(sql, (r[0],)) for r in results: click.secho('@{0[0]}, {0[1]}'.format(r), fg='blue') @activities.command() @click.argument('from_id') @click.argument('to_id') def move_facts(from_id, to_id): """ Move facts from one activity to another """ from_activity = get_activities((from_id,))[0] to_activity = get_activities((to_id,))[0] click.secho( 'Moving facts from "@{0[0]}: {0[1]}" to "@{1[0]}: {1[1]}"'.format( from_activity, to_activity ), fg='green' ) sql = ''' SELECT start_time, activities.name FROM facts LEFT JOIN activities ON facts.activity_id = activities.id WHERE activities.id = ? ''' results = c.execute(sql, (from_id,)) for r in results: click.secho('@{0[0]}, {0[1]}'.format(r), fg='blue') click.confirm('Do you want to continue?', abort=True) c.execute( 'UPDATE facts SET activity_id = ? WHERE activity_id = ?', (to_id, from_id) ) conn.commit() click.secho('Moved {0} facts'.format(results.rowcount), fg='green') @activities.command() def find_duplicates(): """ Show activities which are not unique in their categories """ sql = ''' SELECT categories.id, categories.name, activities.id, activities.name, COUNT(activities.id) c FROM activities LEFT JOIN categories ON activities.category_id = categories.id GROUP BY activities.name, activities.category_id HAVING c > 1 ''' results = c.execute(sql) for r in results: click.secho('@{0[0]}: {0[1]} » @{0[2]}: {0[3]} ({0[4]})'.format(r), fg='blue') @cli.command() def hamster(): click.echo('🐹') if __name__ == "__main__": cli()