Skip to content

Commit

Permalink
Add --status flag to select archived/closed cards, correct use of the…
Browse files Browse the repository at this point in the history
… nested cards resource so that flag takes effect
  • Loading branch information
delucks committed Feb 22, 2020
1 parent dd8a2f4 commit bf185f8
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 31 deletions.
44 changes: 28 additions & 16 deletions gtd.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ def validate_sort(command_context, param, value):


def sorting_fields_command(f):
f = click.option('--fields', callback=validate_fields, help='Choose fields to display by name, comma-separated')(f)
f = click.option('--by', default='activity', callback=validate_sort, help='Choose field to sort')(f)
f = click.option('--fields', callback=validate_fields, help='[Table] display only these fields')(f)
f = click.option('--by', default='activity', callback=validate_sort, help='[Table] sort by this field')(f)
return f


Expand All @@ -200,15 +200,21 @@ def card_filtering_command(f):
f = click.option('-l', '--listname', help='Only show cards from this list', default=None)(f)
f = click.option('--attachments', is_flag=True, help='Only show cards which have attachments', default=None)(f)
f = click.option('--has-due', is_flag=True, help='Only show cards which have due dates', default=None)(f)
f = click.option(
'-s', '--status',
default='visible',
help='Show cards in this state',
type=click.Choice(['all', 'closed', 'open', 'visible'])
)(f)
return f


def json_option(f):
return click.option('-j', '--json', 'use_json', is_flag=True, default=False, help='Output as JSON')(f)
return click.option('-j', '--json', 'use_json', is_flag=True, default=False, help='Output JSON')(f)


def tsv_option(f):
return click.option('--tsv', is_flag=True, default=False, help='Output as tab-separated values')(f)
return click.option('--tsv', is_flag=True, default=False, help='Output tab-separated values')(f)


@click.group(context_settings={'help_option_names': ['-h', '--help']})
Expand Down Expand Up @@ -486,15 +492,16 @@ def show_tags(ctx, use_json, listname):
@tsv_option
@sorting_fields_command
@pass_context
def show_cards(ctx, use_json, tsv, tags, no_tags, match, listname, attachments, has_due, by, fields):
def show_cards(ctx, use_json, tsv, tags, no_tags, match, listname, attachments, has_due, status, by, fields):
'''Display cards
The show command prints a table of all the cards with fields that will fit on the terminal you're using.
You can change this formatting by passing one of --tsv or --json, which will output as a tab-separated value sheet or JSON.
This command along with the batch & review commands share a flexible argument scheme for getting card information.
Mutually exclusive arguments include -t/--tags & --no-tags along with -j/--json & --tsv
You can change this formatting by passing one of --tsv or --json, which will output as a tab-separated value sheet
or JSON. This command along with the batch & review commands share a flexible argument scheme for getting card
information. Mutually exclusive arguments include -t/--tags & --no-tags along with -j/--json & --tsv
'''
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand All @@ -514,7 +521,7 @@ def show_cards(ctx, use_json, tsv, tags, no_tags, match, listname, attachments,
@tsv_option
@pass_context
def show_soon(ctx, use_json, tsv):
cards = CardView.create(ctx, has_due_date=True)
cards = CardView.create(ctx, status='visible', has_due_date=True)
if use_json:
print(cards.json())
else:
Expand Down Expand Up @@ -567,12 +574,13 @@ def delete_tag(ctx, name, noninteractive):
@click.option('-n', '--noninteractive', is_flag=True, default=False, help='Do not prompt before deleting')
@card_filtering_command
@pass_context
def delete_cards(ctx, force, noninteractive, tags, no_tags, match, listname, attachments, has_due):
def delete_cards(ctx, force, noninteractive, tags, no_tags, match, listname, attachments, has_due, status):
'''Delete a set of cards specified
'''
ctx.display.banner()
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand Down Expand Up @@ -692,7 +700,7 @@ def grep(ctx, pattern, insensitive, count, regexp, by, fields, use_json):
elif pattern:
final_pattern = pattern
flags = re.I if insensitive else 0
cards = CardView.create(ctx, title_regex=final_pattern, regex_flags=flags)
cards = CardView.create(ctx, status='visible', title_regex=final_pattern, regex_flags=flags)
if count:
print(sum(1 for _ in cards))
return
Expand All @@ -718,10 +726,11 @@ def batch():
@batch.command('move')
@card_filtering_command
@pass_context
def batch_move(ctx, tags, no_tags, match, listname, attachments, has_due):
def batch_move(ctx, tags, no_tags, match, listname, attachments, has_due, status):
'''Change the list of each card selected'''
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand All @@ -739,10 +748,11 @@ def batch_move(ctx, tags, no_tags, match, listname, attachments, has_due):
@batch.command('tag')
@card_filtering_command
@pass_context
def batch_tag(ctx, tags, no_tags, match, listname, attachments, has_due):
def batch_tag(ctx, tags, no_tags, match, listname, attachments, has_due, status):
'''Change tags on each card selected'''
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand All @@ -759,10 +769,11 @@ def batch_tag(ctx, tags, no_tags, match, listname, attachments, has_due):
@batch.command('due')
@card_filtering_command
@pass_context
def batch_due(ctx, tags, no_tags, match, listname, attachments, has_due):
def batch_due(ctx, tags, no_tags, match, listname, attachments, has_due, status):
'''Set due date for all cards selected'''
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand All @@ -781,7 +792,7 @@ def batch_due(ctx, tags, no_tags, match, listname, attachments, has_due):
@pass_context
def batch_attach(ctx):
'''Extract HTTP links from card titles'''
cards = CardView.create(ctx, title_regex=VALID_URL_REGEX)
cards = CardView.create(ctx, status='visible', title_regex=VALID_URL_REGEX)
ctx.display.banner()
for card in cards:
ctx.display.show_card(card)
Expand All @@ -795,13 +806,14 @@ def batch_attach(ctx):
@cli.command(short_help='Use a smart repl-like menu')
@card_filtering_command
@pass_context
def review(ctx, tags, no_tags, match, listname, attachments, has_due):
def review(ctx, tags, no_tags, match, listname, attachments, has_due, status):
'''show a smart, command-line based menu for each card selected.
This menu will prompt you to add tags to untagged cards, to attach the title
of cards which have a link in the title, and gives you all the other functionality combined.
'''
cards = CardView.create(
ctx,
status=status,
tags=tags,
no_tags=no_tags,
title_regex=match,
Expand Down
28 changes: 14 additions & 14 deletions todo/card.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from prompt_toolkit.validation import Validator
from prompt_toolkit.completion import WordCompleter, FuzzyWordCompleter

from todo.connection import Connection
from todo.connection import TrelloConnection
from todo.exceptions import GTDException
from todo.input import prompt_for_confirmation, single_select
from todo.misc import get_title_of_webpage, DevNullRedirect, VALID_URL_REGEX, return_on_eof, build_name_lookup
Expand All @@ -39,7 +39,7 @@ class Card:
unless you call Card.fetch() to refresh the base JSON structure.
'''

def __init__(self, connection: Connection, card_json: dict):
def __init__(self, connection: TrelloConnection, card_json: dict):
self.card_json = card_json
self.connection = connection

Expand Down Expand Up @@ -366,15 +366,15 @@ def create(context, **kwargs):
# Establish all base filters for cards nested resource query parameters.
query_params = {}
regex_flags = kwargs.get('regex_flags', 0)
# Card status: open/closed/archived/all
if (status := kwargs.get('status', None)) is not None: # noqa
valid_filters = ['all', 'closed', 'open', 'visible']
if status not in valid_filters:
click.secho(f'Card filter {status} is not valid! Use one of {",".join(valid_filters)}')
raise GTDException(1)
query_params['cards'] = status
# Card status, in nested card resource
status = kwargs.get('status', 'visible')
valid_filters = ['all', 'closed', 'open', 'visible']
if status not in valid_filters:
click.secho(f'Card filter {status} is not valid! Use one of {",".join(valid_filters)}')
raise GTDException(1)
query_params['cards'] = status
# TODO common field selection? Might be able to avoid ones that we don't use at all
# query_params['fields'] = 'all'
query_params['card_fields'] = 'all'
target_cards = []
if (list_regex := kwargs.get('list_regex', None)) is not None: # noqa
# Are lists passed? If so, query to find out the list IDs corresponding to the names we have
Expand All @@ -386,14 +386,14 @@ def create(context, **kwargs):
target_list_ids.append(list_object['id'])
# Iteratively pull IDs from each list, passing the common parameters to them
for list_id in target_list_ids:
cards_json = context.connection.trello.fetch_json(f'/lists/{list_id}/cards', query_params=query_params)
target_cards.extend(cards_json)
cards_json = context.connection.trello.fetch_json(f'/lists/{list_id}', query_params=query_params)
target_cards.extend(cards_json['cards'])
else:
# If no lists are passed, call the board's card resource
cards_json = context.connection.trello.fetch_json(
f'/boards/{context.board.id}/cards', query_params=query_params
f'/boards/{context.board.id}', query_params=query_params
)
target_cards.extend(cards_json)
target_cards.extend(cards_json['cards'])

# Post-process the returned JSON, filtering down to the other passed parameters
filters = []
Expand Down
2 changes: 1 addition & 1 deletion todo/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def lists_by_id(self):
'''Return a mapping of list names to IDs on the main board, so that cards can have their
lists shown without making a network call to retrieve the list names.
'''
return {l['id']: l['name'] for l in self.main_lists()}
return {l['id']: l['name'] for l in self.main_lists(status_filter='all', force=True)}

def inbox_list(self):
'''use the configuration to get the main board & list from
Expand Down

0 comments on commit bf185f8

Please sign in to comment.