summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcal.py42
-rwxr-xr-xtests/tests_kal.sh45
2 files changed, 74 insertions, 13 deletions
diff --git a/cal.py b/cal.py
index 88ce91b..6b3e701 100755
--- a/cal.py
+++ b/cal.py
@@ -45,7 +45,7 @@ from lib.template import Template
## /usr/lib/*/site-packages/click/types.py on how to do this.
## TODO: maybe find those attributes through the icalendar library? icalendar.cal.singletons, icalendar.cal.multiple, etc
-attr_txt_one = ['location', 'description', 'geo', 'organizer', 'summary']
+attr_txt_one = ['location', 'description', 'geo', 'organizer', 'summary', 'class']
attr_txt_many = ['category', 'comment', 'contact', 'resources']
def parse_dt(input, return_type=None):
@@ -205,8 +205,11 @@ def _set_attr_options(verb=""):
@click.option('--start', help='do a time search, with this start timestamp')
@click.option('--end', help='do a time search, with this end timestamp (or duration)')
@click.option('--timespan', help='do a time search for this interval')
+@click.option('--sort-key', help='use this attributes for sorting. Templating can be used. Prepend with - for reverse sort', multiple=True)
+@click.option('--limit', help='Number of objects to show', type=int)
+@click.option('--offset', help='SKip the first objects', type=int)
@click.pass_context
-def select(ctx, all, uid, abort_on_missing_uid, **kwargs_):
+def select(ctx, all, uid, abort_on_missing_uid, sort_key, limit, offset, **kwargs_):
"""
select/search/filter tasks/events, for listing/editing/deleting, etc
"""
@@ -232,7 +235,7 @@ def select(ctx, all, uid, abort_on_missing_uid, **kwargs_):
missing_uids = []
for uid_ in uid:
comp_filter=None
- if kwargs['event']:
+ if kwargs_['event']:
comp_filter='VEVENT'
if kwargs_['todo']:
comp_filter='VTODO'
@@ -270,6 +273,28 @@ def select(ctx, all, uid, abort_on_missing_uid, **kwargs_):
for c in ctx.obj['calendars']:
objs.extend(c.search(**kwargs))
+ ## OPTIMIZE TODO: sorting the list multiple times rather than once is a bit of brute force, if there are several sort keys and long list of objects, we should sort once and consider all sort keys while sorting
+ ## TODO: Consider that an object may be expanded and contain lots of event instances. We will then need to expand the caldav.Event object into multiple objects, each containing one recurrance instance. This should probably be done on the caldav side of things.
+ for skey in reversed(sort_key):
+ ## If the key starts with -, sorting should be reversed
+ if skey[0] == '-':
+ reverse = True
+ skey=skey[1:]
+ else:
+ reverse = False
+ ## if the key contains {}, it should be considered to be a template
+ if '{' in skey:
+ fkey = lambda obj: Template(skey).format(**obj.icalendar_instance.subcomponents[0])
+ else:
+ fkey = lambda obj: obj.icalendar_instance.subcomponents[0][skey]
+ ctx.obj['objs'].sort(key=fkey, reverse=reverse)
+
+ ## OPTIMIZE TODO: this is also suboptimal, if ctx.obj is a very long list
+ if offset is not None:
+ ctx.obj['objs'] = ctx.obj['objs'][offset:]
+ if limit is not None:
+ ctx.obj['objs'] = ctx.obj['objs'][0:limit]
+
@select.command()
@click.option('--ics/--no-ics', default=False, help="Output in ics format")
@click.option('--template', default="{DUE.dt:?{DTSTART.dt:?(date missing)?}?:%F %H:%M:%S}: {SUMMARY:?{DESCRIPTION:?(no summary given)?}?}")
@@ -308,9 +333,10 @@ def delete(ctx, multi_delete, **kwargs):
@select.command()
@click.option('--add-category', default=None, help="Delete multiple things without confirmation prompt", multiple=True)
+@click.option('--complete/--uncomplete', default=None, help="Mark task(s) as completed")
@_set_attr_options(verb='set')
@click.pass_context
-def edit(ctx, add_category=None, **kwargs):
+def edit(ctx, add_category=None, complete=None, **kwargs):
_process_set_args(ctx, kwargs)
for obj in ctx.obj['objs']:
ie = obj.icalendar_instance.subcomponents[0]
@@ -325,7 +351,11 @@ def edit(ctx, add_category=None, **kwargs):
cats = []
cats.extend(add_category)
ie.add('categories', cats)
- obj.save()
+ if complete:
+ obj.complete()
+ elif complete is False:
+ obj.uncomplete()
+ obj.save()
@select.command()
@@ -393,7 +423,7 @@ def _process_set_args(ctx, kwargs):
ctx.obj['set_args'][x[4:]] = kwargs[x]
if 'summary' in kwargs:
ctx.obj['set_args']['summary'] = ctx.obj['set_args'].get('summary', '') + kwargs['summary']
- if kwargs['ical_fragment']:
+ if 'ical_fragment' in kwargs:
ctx.obj['set_args']['ics'] = kwargs['ical_fragment']
@add.command()
diff --git a/tests/tests_kal.sh b/tests/tests_kal.sh
index 3858063..efd73ec 100755
--- a/tests/tests_kal.sh
+++ b/tests/tests_kal.sh
@@ -158,9 +158,11 @@ fi
echo "## TODOS / TASK LISTS"
echo "## Attempting to add a task with category 'scripttest'"
-kal add todo --set-category scripttest "edit this task"
+kal add todo --set-class=PUBLIC --set-category scripttest "edit this task"
uidtodo1=$(echo $output | perl -ne '/uid=(.*)$/ && print $1')
-kal add todo --set-category scripttest "edit this task2"
+kal add todo --set-class=CONFIDENTIAL --set-category scripttest "edit this task2"
+uidtodo2=$(echo $output | perl -ne '/uid=(.*)$/ && print $1')
+kal add todo --set-class=PRIVATE "another task for testing sorting, offset and limit"
uidtodo2=$(echo $output | perl -ne '/uid=(.*)$/ && print $1')
echo "## Listing out all tasks with category set to 'scripttest'"
@@ -180,16 +182,43 @@ kal select --todo --category scripttest3 list
kal select --todo --comment editing list
[ $(echo "$output" | wc -l) == 1 ] && echo "## OK: found the todo item we just edited and nothing more"
-if [ -n "" ]; then
+echo "## Sort order and limit. CONFIDENTIAL class should come first. Only one task should be returned"
+kal select --todo --sort-key=CLASS --limit 1 list --template '{CLASS}'
+echo "$output" | grep -q CONFIDENTIAL || error "Sorting does not work as expected"
+echo "$output" | grep -q PRIVATE && error "Limit does not work as expected"
+
+echo "## Offset. PRIVATE should come in the middle"
+kal select --todo --sort-key=class --limit 1 --offset 1 list --template '{CLASS}'
+echo "$output" | grep -q PRIVATE || error "Offset does not work as expected"
+
+echo "## Reverse order. PUBLIC should come first"
+kal select --todo --sort-key=-CLASS --limit 1 list --template '{CLASS}'
+echo "$output" | grep -q PUBLIC || error "Reverse sort does not work as expected"
+
+echo "## Templating. The task without category should come first or last"
+kal select --todo --sort-key='{CATEGORIES.cats[0]:?aaa?}' --limit 1 list --template '{SUMMARY}'
+echo "$output" | grep -q 'another task' || error "sort by template not working as expected"
+kal select --todo --sort-key='{CATEGORIES.cats[0]:?zzz?}' --limit 1 list --template '{SUMMARY}'
+echo "$output" | grep -q 'another task' && error "sort by template not working as expected"
+
+## TODO: add tests for limit!=1 and no limit
+## TODO: add tests for multiple sort keys
+
echo "## Complete the task"
-calendar_cli todo --categories scripttest complete
-calendar_cli todo --categories scripttest list
+kal select --todo --category scripttest edit --complete
+kal select --todo --category scripttest list
[ -z "$output" ] && echo "## OK: todo-item is done"
-calendar_cli todo --todo-uid $uidtodo1 delete
+echo "## Test that we can list out completed tasks, and also undo completion"
+kal select --todo --category scripttest --include-completed edit --uncomplete
+kal select --todo --category scripttest list
+[ -z "$output" ] && error "--uncomplete does not work!"
+kal select --todo --uid $uidtodo1 delete
+
+if [ -n "" ]; then
## parent-child relationships
echo "## Going to add three todo-items with children/parent relationships"
-calendar_cli todo add --set-categories scripttest "this is a grandparent"
+calendar_cli todo add --ste-categories scripttest "this is a grandparent"
uidtodo2=$(echo $output | perl -ne '/uid=(.*)$/ && print $1')
calendar_cli todo --categories=scripttest add --set-categories scripttest --is-child "this is a parent and a child"
uidtodo3=$(echo $output | perl -ne '/uid=(.*)$/ && print $1')
@@ -210,6 +239,8 @@ calendar_cli todo --hide-parents --categories scripttest complete
calendar_cli todo --hide-parents --categories scripttest list
[ -z "$output" ] && echo "## OK: found no tasks now"
+## TODO: test completion of recurring task
+
fi
echo "## some kal TESTS COMPLETED SUCCESSFULLY! YAY!"