示例#1
0
    def _set(self, key, value):
        if value is None and key in self._data:
            del self._data[key]
        elif self._data.get(key) != value:
            self._data[key] = value
        else:
            return

        workflow().store_data('prefs', self._data)
示例#2
0
def filter(args):
    util.workflow().add_item(
        'Are you sure?',
        'You will need to log in to a Wunderlist account to continue using the workflow',
        arg=' '.join(args),
        valid=True,
        icon=icons.CHECKMARK)

    util.workflow().add_item('Nevermind', autocomplete='', icon=icons.CANCEL)
    def __init__(self, data):
        self._data = data or {}

        # Clean up old prerelease preference
        if 'prerelease_channel' in self._data:
            # Migrate to the alfred-workflow preference
            self.prerelease_channel = self._data['prerelease_channel']
            del self._data['prerelease_channel']

            workflow().store_data('prefs', self._data)
示例#4
0
def filter(args):
	list_name = _list_name(args)
	subtitle = list_name if list_name else 'Type the name of the list'

	util.workflow().add_item('New list...', subtitle, arg='--stored-query', valid=list_name != '', icon=icons.LIST_NEW)

	util.workflow().add_item(
		'Main menu',
		autocomplete='', icon=icons.BACK
	)
示例#5
0
文件: auth.py 项目: Alfr0475/alfred.d
def new_oauth_state():
	import random
	import string

	state_length = 20
	state = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(state_length))

	workflow().save_password(config.KC_OAUTH_STATE, state)

	return state
示例#6
0
    def __init__(self, data):
        self._data = data or {}

        # Clean up old prerelease preference
        if 'prerelease_channel' in self._data:
            # Migrate to the alfred-workflow preference
            self.prerelease_channel = self._data['prerelease_channel']
            del self._data['prerelease_channel']

            workflow().store_data('prefs', self._data)
示例#7
0
def filter(args):
    list_name = _list_name(args)
    subtitle = list_name if list_name else 'Type the name of the list'

    util.workflow().add_item('New list...',
                             subtitle,
                             arg='--stored-query',
                             valid=list_name != '',
                             icon=icons.LIST_NEW)

    util.workflow().add_item('Main menu', autocomplete='', icon=icons.BACK)
def new_oauth_state():
    import random
    import string

    state_length = 20
    state = ''.join(random.SystemRandom().choice(string.ascii_uppercase +
                                                 string.digits)
                    for _ in range(state_length))

    workflow().save_password(config.KC_OAUTH_STATE, state)

    return state
示例#9
0
def route(args):
	handler = None
	command = []
	command_string = ''
	action = ''

	# Read the stored query, which will correspond to the user's alfred query
	# as of the very latest keystroke. This may be different than the query
	# when this script was launched due to the startup latency.
	if args[0] == '--stored-query':
		query_file = workflow().workflowfile('.query')
		with open(query_file, 'r') as f:
			command_string = workflow().decode(f.read())
		os.remove(query_file)
	# Otherwise take the command from the first command line argument
	elif args:
		command_string = args[0]

	command = command_string.split(' ')

	if command:
		action = command[0]

	if not is_authorized():
		from wunderlist.handlers import login
		handler = login
	elif action == ':list':
		from wunderlist.handlers import lists
		handler = lists
	elif action == ':logout':
		from wunderlist.handlers import logout
		handler = logout
	elif action == ':pref':
		from wunderlist.handlers import preferences
		handler = preferences
	elif action == ':about':
		from wunderlist.handlers import about
		handler = about
	# If the command starts with a space (no special keywords), the workflow
	# creates a new task
	elif command_string and command_string[0] == ' ':
		from wunderlist.handlers import tasks
		handler = tasks
	else:
		from wunderlist.handlers import welcome
		handler = welcome

	if handler:
		if '--commit' in args:
			handler.commit(command)
		else:
			handler.filter(command)

			if workflow().update_available:
				update_data = workflow().cached_data('__workflow_update_status', max_age=0)

				if '0.5.3' != update_data.get('version'):
					workflow().add_item('An update is available!', 'Update the Wunderlist workflow from version 0.5.3 to %s' % update_data.get('version'), arg=':about update', valid=True, icon=icons.DOWNLOAD)

			workflow().send_feedback()
示例#10
0
def filter(args):
	backgroundSync()

	workflow().add_item(
		'New task...',
		'Begin typing to add a new task',
		autocomplete=' ',
		icon=icons.TASK_COMPLETED
	)

	workflow().add_item(
		'New list',
		autocomplete=':list ',
		icon=icons.LIST_NEW
	)

	workflow().add_item(
		'Preferences',
		autocomplete=':pref ',
		icon=icons.PREFERENCES
	)

	workflow().add_item(
		'About',
		'Learn about the workflow and get support',
		autocomplete=':about ',
		icon=icons.INFO
	)
示例#11
0
def filter(args):
    util.workflow().add_item(
        'Are you sure?',
        'You will need to log in to a Wunderlist account to continue using the workflow',
        arg=' '.join(args),
        valid=True,
        icon=icons.CHECKMARK
    )

    util.workflow().add_item(
        'Nevermind',
        autocomplete='',
        icon=icons.CANCEL
    )
def resolve_oauth_token(code):
    import requests

    url = '%s/%s' % (config.WL_OAUTH_URL, 'access_token')
    data = {
        'code': code,
        'client_id': config.WL_CLIENT_ID,
        'client_secret': config.WL_CLIENT_SECRET
    }

    res = requests.post(url=url, data=data)
    token_info = res.json()

    workflow().save_password(config.KC_OAUTH_TOKEN, token_info['access_token'])
    workflow().delete_password(config.KC_OAUTH_STATE)
示例#13
0
文件: list.py 项目: Alfr0475/alfred.d
	def sync(cls):
		from wunderlist.api import lists

		instances = []

		try:
			instances = cls.select()
		except:
			pass

		lists_data = lists.lists()

		cls._perform_updates(instances, lists_data)

		workflow().store_data('lists', lists_data)
示例#14
0
文件: auth.py 项目: amatiasq/dotfiles
def resolve_oauth_token(code):
    import requests

    url = '%s/%s' % (config.WL_OAUTH_URL, 'access_token')
    data = {
        'code': code,
        'client_id': config.WL_CLIENT_ID,
        'client_secret': config.WL_CLIENT_SECRET
    }

    res = requests.post(url=url, data=data)
    token_info = res.json()

    workflow().save_password(config.KC_OAUTH_TOKEN, token_info['access_token'])
    workflow().delete_password(config.KC_OAUTH_STATE)
示例#15
0
def alfred_is_dark():
	# Formatted rgba(255,255,255,0.90)
	background_rgba = workflow().alfred_env['theme_background']
	if background_rgba:
		rgb = [int(x) for x in background_rgba[5:-6].split(',')]
		return (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255 < 0.5
	return False
示例#16
0
def alfred_is_dark():
    # Formatted rgba(255,255,255,0.90)
    background_rgba = workflow().alfred_env['theme_background']
    if background_rgba:
        rgb = [int(x) for x in background_rgba[5:-6].split(',')]
        return (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]) / 255 < 0.5
    return False
def background_sync():
    from workflow.background import run_in_background
    task_id = 'sync'

    # Only runs if another sync is not already in progress
    run_in_background(task_id, [
        '/usr/bin/env',
        'python',
        workflow().workflowfile('alfred-wunderlist-workflow.py'),
        'pref sync background',
        '--commit'
    ])
示例#18
0
文件: sync.py 项目: Alfr0475/alfred.d
def backgroundSync():
	from workflow.background import run_in_background
	from wunderlist.util import workflow

	# Only runs if another sync is not already in progress
	run_in_background('sync', [
		'/usr/bin/env',
		'python',
		workflow().workflowfile('alfred-wunderlist-workflow.py'),
		':pref sync',
		'--commit'
	])
def authorize():
    from multiprocessing import Process
    import urllib
    import webbrowser

    workflow().store_data('auth', 'started')

    state = new_oauth_state()
    data = urllib.urlencode({
        'client_id': config.WL_CLIENT_ID,
        'redirect_uri': 'http://localhost:6200',
        'state': state
    })
    url = '%s/%s?%s' % (config.WL_OAUTH_URL, 'authorize', data)

    # Start a server to await the redirect URL request after authorizing
    server = Process(target=await_token)
    server.start()

    # Open the authorization prompt in the default web browser
    webbrowser.open(url)
示例#20
0
文件: auth.py 项目: amatiasq/dotfiles
def authorize():
    from multiprocessing import Process
    import urllib
    import webbrowser

    workflow().store_data('auth', 'started')

    state = new_oauth_state()
    data = urllib.urlencode({
        'client_id': config.WL_CLIENT_ID,
        'redirect_uri': 'http://localhost:6200',
        'state': state
    })
    url = '%s/%s?%s' % (config.WL_OAUTH_URL, 'authorize', data)

    # Start a server to await the redirect URL request after authorizing
    server = Process(target=await_token)
    server.start()

    # Open the authorization prompt in the default web browser
    webbrowser.open(url)
    def sync(cls):
        from wunderlist.api import lists
        start = time.time()

        lists_data = lists.lists()
        instances = []

        log.info('Retrieved all %d lists in %s', len(lists_data),
                 time.time() - start)
        start = time.time()

        workflow().store_data('lists', lists_data)

        try:
            instances = cls.select(cls.id, cls.revision, cls.title)
        except PeeweeException:
            pass

        log.info('Loaded all %d lists from the database in %s', len(instances),
                 time.time() - start)

        return cls._perform_updates(instances, lists_data)
示例#22
0
def commit(args):
	if 'update' in args:
		if workflow().start_update():
			print 'The workflow is being updated'
		else:
			print 'You already have the latest workflow version'
	elif 'changelog' in args:
		import webbrowser

		webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/releases/tag/0.5.3')
	elif 'issues' in args:
		import webbrowser

		webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/issues')
示例#23
0
文件: auth.py 项目: amatiasq/dotfiles
def handle_authorization_url(url):
    import urlparse

    # Parse query data & params to find out what was passed
    parsed_url = urlparse.urlparse(url)
    params = urlparse.parse_qs(parsed_url.query)

    # request is either for a file to be served up or our test
    if 'code' in params and validate_oauth_state(params['state'][0]):
        # Request a token based on the code
        resolve_oauth_token(params['code'][0])
        workflow().store_data('auth', None)

        print 'You are now logged in'
        return True
    elif 'error' in params:
        workflow().store_data('auth', 'Error: %s' % params['error'])

        print 'Please try again later'
        return params['error']

    # Not a valid URL
    return False
def handle_authorization_url(url):
    import urlparse

    # Parse query data & params to find out what was passed
    parsed_url = urlparse.urlparse(url)
    params = urlparse.parse_qs(parsed_url.query)

    # request is either for a file to be served up or our test
    if 'code' in params and validate_oauth_state(params['state'][0]):
        # Request a token based on the code
        resolve_oauth_token(params['code'][0])
        workflow().store_data('auth', None)

        print 'You are now logged in'
        return True
    elif 'error' in params:
        workflow().store_data('auth', 'Error: %s' % params['error'])

        print 'Please try again later'
        return params['error']

    # Not a valid URL
    return False
def commit(args, modifier=None):
    if 'update' in args:
        if workflow().start_update():
            print 'The workflow is being updated'
        else:
            print 'You already have the latest workflow version'
    else:
        import webbrowser

        if 'changelog' in args:
            webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/releases/tag/__VERSION__')
        elif 'wunderlist' in args:
            webbrowser.open('https://www.wunderlist.com/')
        elif 'issues' in args:
            webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/issues')
示例#26
0
def commit(args, modifier=None):
    if 'update' in args:
        if workflow().start_update():
            print 'The workflow is being updated'
        else:
            print 'You already have the latest workflow version'
    else:
        import webbrowser

        if 'changelog' in args:
            webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/releases/tag/0.7.0')
        elif 'wunderlist' in args:
            webbrowser.open('https://www.wunderlist.com/')
        elif 'issues' in args:
            webbrowser.open('https://github.com/idpaterson/alfred-wunderlist-workflow/issues')
示例#27
0
def commit(args):
	workflow = util.workflow()
	started_auth = workflow.stored_data('auth')
	manual_verification_url = re.search(r'http://\S+', ' '.join(args))

	if started_auth and manual_verification_url:
		auth_status = auth.handle_authorization_url(manual_verification_url.group())

		if auth_status is True:
			# Reopen the workflow
			import subprocess
			subprocess.call(['/usr/bin/env', 'osascript', 'bin/launch_alfred.scpt', 'wl'])
		elif not auth_status:
			print 'Invalid or expired URL, please try again'
	else:
		auth.authorize()
示例#28
0
def filter(args):
	workflow().add_item(
		'New in this version',
		'Installed: 0.5.3   See the changes from the previous version',
		arg=':about changelog', valid=True, icon=icons.INFO
	)

	workflow().add_item(
		'Questions or concerns?',
		'See outstanding issues and report your own bugs or feedback',
		arg=':about issues', valid=True, icon=icons.HELP
	)

	workflow().add_item(
		'Update workflow',
		'Check for updates to the workflow (automatically checked periodically)',
		arg=':about update', valid=True, icon=icons.DOWNLOAD
	)

	workflow().add_item(
		'Main menu',
		autocomplete='', icon=icons.BACK
	)
def filter(args):
    workflow().add_item(
        'New in this version',
        'Installed: __VERSION__   See the changes from the previous version',
        arg='-about changelog',
        valid=True,
        icon=icons.INFO)

    workflow().add_item(
        'Questions or concerns?',
        'See outstanding issues and report your own bugs or feedback',
        arg='-about issues',
        valid=True,
        icon=icons.HELP)

    workflow().add_item(
        'Update workflow',
        'Check for updates to the workflow (automatically checked periodically)',
        arg='-about update',
        valid=True,
        icon=icons.DOWNLOAD)

    workflow().add_item('Main menu', autocomplete='', icon=icons.BACK)
示例#30
0
def filter(args):
	workflow = util.workflow()
	started_auth = workflow.stored_data('auth')
	manual_verification_url = re.search(r'http://\S+', ' '.join(args))

	if not (started_auth and manual_verification_url):
		workflow.add_item(
			'Please log in',
			'Authorize Alfred Wunderlist Workflow to use your Wunderlist account',
			valid=True,
			icon=icons.ACCOUNT
		)

	# If the auth process has started, allow user to paste a key manually
	if started_auth:
		workflow.add_item(
			'Having trouble?',
			'Paste the full http://localhost:6200 URL from your browser then press the return key to continue',
			autocomplete=None if manual_verification_url else ' http://localhost:6200/?',
			arg=manual_verification_url.group() if manual_verification_url else None,
			valid=manual_verification_url,
			icon=icons.HELP
		)
示例#31
0
from copy import copy
import logging
import time

from dateutil import parser
from peewee import (DateField, DateTimeField, ForeignKeyField, Model,
                    SqliteDatabase, TimeField)

from wunderlist.util import workflow, NullHandler

log = logging.getLogger(__name__)
log.addHandler(NullHandler())

db = SqliteDatabase(workflow().datadir + '/wunderlist.db', threadlocals=True)

def _balance_keys_for_insert(values):
    all_keys = set()
    for v in values:
        all_keys.update(v)

    balanced_values = []
    for v in values:
        balanced = {}
        for k in all_keys:
            balanced[k] = v.get(k)
        balanced_values.append(balanced)

    return balanced_values

class BaseModel(Model):
def oauth_token():
    try:
        return workflow().get_password(config.KC_OAUTH_TOKEN)
    except PasswordNotFound:
        return None
示例#33
0
def filter(args):
    task = _task(args)
    subtitle = task_subtitle(task)
    wf = workflow()
    matching_hashtags = []

    if not task.title:
        subtitle = 'Begin typing to add a new task'

    # Preload matching hashtags into a list so that we can get the length
    if task.has_hashtag_prompt:
        from wunderlist.models.hashtag import Hashtag

        hashtags = Hashtag.select().where(Hashtag.id.contains(task.hashtag_prompt.lower())).order_by(fn.Lower(Hashtag.tag).asc())

        for hashtag in hashtags:
            matching_hashtags.append(hashtag)

    # Show hashtag prompt if there is more than one matching hashtag or the
    # hashtag being typed does not exactly match the single matching hashtag
    if task.has_hashtag_prompt and len(matching_hashtags) > 0 and (len(matching_hashtags) > 1 or task.hashtag_prompt != matching_hashtags[0].tag):
        for hashtag in matching_hashtags:
            wf.add_item(hashtag.tag[1:], '', autocomplete=' ' + task.phrase_with(hashtag=hashtag.tag) + ' ', icon=icons.HASHTAG)

    elif task.has_list_prompt:
        lists = wf.stored_data('lists')
        if lists:
            for list in lists:
                # Show some full list names and some concatenated in command
                # suggestions
                sample_command = list['title']
                if random() > 0.5:
                    sample_command = sample_command[:int(len(sample_command) * .75)]
                icon = icons.INBOX if list['list_type'] == 'inbox' else icons.LIST
                wf.add_item(list['title'], 'Assign task to this list, e.g. %s: %s' % (sample_command.lower(), task.title), autocomplete=' ' + task.phrase_with(list_title=list['title']), icon=icon)
            wf.add_item('Remove list', 'Tasks without a list are added to the Inbox', autocomplete=' ' + task.phrase_with(list_title=False), icon=icons.CANCEL)
        elif is_running('sync'):
            wf.add_item('Your lists are being synchronized', 'Please try again in a few moments', autocomplete=' ' + task.phrase_with(list_title=False), icon=icons.BACK)

    # Task has an unfinished recurrence phrase
    elif task.has_recurrence_prompt:
        wf.add_item('Every month', 'Same day every month, e.g. every mo', uid="recurrence_1m", autocomplete=' %s ' % task.phrase_with(recurrence='every month'), icon=icons.RECURRENCE)
        wf.add_item('Every week', 'Same day every week, e.g. every week, every Tuesday', uid="recurrence_1w", autocomplete=' %s ' % task.phrase_with(recurrence='every week'), icon=icons.RECURRENCE)
        wf.add_item('Every year', 'Same date every year, e.g. every 1 y, every April 15', uid="recurrence_1y", autocomplete=' %s ' % task.phrase_with(recurrence='every year'), icon=icons.RECURRENCE)
        wf.add_item('Every 3 months', 'Same day every 3 months, e.g. every 3 months', uid="recurrence_3m", autocomplete=' %s ' % task.phrase_with(recurrence='every 3 months'), icon=icons.RECURRENCE)
        wf.add_item('Remove recurrence', autocomplete=' ' + task.phrase_with(recurrence=False), icon=icons.CANCEL)

    # Task has an unfinished due date phrase
    elif task.has_due_date_prompt:
        wf.add_item('Today', 'e.g. due today', autocomplete=' %s ' % task.phrase_with(due_date='due today'), icon=icons.TODAY)
        wf.add_item('Tomorrow', 'e.g. due tomorrow', autocomplete=' %s ' % task.phrase_with(due_date='due tomorrow'), icon=icons.TOMORROW)
        wf.add_item('Next Week', 'e.g. due next week', autocomplete=' %s ' % task.phrase_with(due_date='due next week'), icon=icons.NEXT_WEEK)
        wf.add_item('Next Month', 'e.g. due next month', autocomplete=' %s ' % task.phrase_with(due_date='due next month'), icon=icons.CALENDAR)
        wf.add_item('Next Year', 'e.g. due next year, due April 15', autocomplete=' %s ' % task.phrase_with(due_date='due next year'), icon=icons.CALENDAR)
        wf.add_item('Remove due date', 'Add "not due" to fix accidental dates, or see wl-pref', autocomplete=' ' + task.phrase_with(due_date=False), icon=icons.CANCEL)

    # Task has an unfinished reminder phrase
    elif task.has_reminder_prompt:
        prefs = Preferences.current_prefs()
        default_reminder_time = format_time(prefs.reminder_time, 'short')
        due_date_hint = ' on the due date' if task.due_date else ''
        wf.add_item('Reminder at %s%s' % (default_reminder_time, due_date_hint), 'e.g. r %s' % default_reminder_time, autocomplete=' %s ' % task.phrase_with(reminder_date='remind me at %s' % format_time(prefs.reminder_time, 'short')), icon=icons.REMINDER)
        wf.add_item('At noon%s' % due_date_hint, 'e.g. reminder noon', autocomplete=' %s ' % task.phrase_with(reminder_date='remind me at noon'), icon=icons.REMINDER)
        wf.add_item('At 8:00 PM%s' % due_date_hint, 'e.g. remind at 8:00 PM', autocomplete=' %s ' % task.phrase_with(reminder_date='remind me at 8:00pm'), icon=icons.REMINDER)
        wf.add_item('At dinner%s' % due_date_hint, 'e.g. alarm at dinner', autocomplete=' %s ' % task.phrase_with(reminder_date='remind me at dinner'), icon=icons.REMINDER)
        wf.add_item('Today at 6:00 PM', 'e.g. remind me today at 6pm', autocomplete=' %s ' % task.phrase_with(reminder_date='remind me today at 6:00pm'), icon=icons.REMINDER)
        wf.add_item('Remove reminder', autocomplete=' ' + task.phrase_with(reminder_date=False), icon=icons.CANCEL)

    # Main menu for tasks
    else:
        wf.add_item(task.list_title + u' – create a new task...', subtitle, modifier_subtitles={
            'alt': u'…then edit it in the Wunderlist app    %s' % subtitle
        }, arg='--stored-query', valid=task.title != '', icon=icons.TASK)

        title = 'Change list' if task.list_title else 'Select a list'
        wf.add_item(title, 'Prefix the task, e.g. Automotive: ' + task.title, autocomplete=' ' + task.phrase_with(list_title=True), icon=icons.LIST)

        title = 'Change the due date' if task.due_date else 'Set a due date'
        wf.add_item(title, '"due" followed by any date-related phrase, e.g. due next Tuesday; due May 4', autocomplete=' ' + task.phrase_with(due_date=True), icon=icons.CALENDAR)

        title = 'Change the recurrence' if task.recurrence_type else 'Make it a recurring task'
        wf.add_item(title, '"every" followed by a unit of time, e.g. every 2 months; every year; every 4w', autocomplete=' ' + task.phrase_with(recurrence=True), icon=icons.RECURRENCE)

        title = 'Change the reminder' if task.reminder_date else 'Set a reminder'
        wf.add_item(title, '"remind me" followed by a time and/or date, e.g. remind me at noon; r 10am; alarm 8:45p', autocomplete=' ' + task.phrase_with(reminder_date=True), icon=icons.REMINDER)

        if task.starred:
            wf.add_item('Remove star', 'Remove * from the task', autocomplete=' ' + task.phrase_with(starred=False), icon=icons.STAR_REMOVE)
        else:
            wf.add_item('Star', 'End the task with * (asterisk)', autocomplete=' ' + task.phrase_with(starred=True), icon=icons.STAR)

        wf.add_item('Main menu', autocomplete='', icon=icons.BACK)
示例#34
0
文件: base.py 项目: Alfr0475/alfred.d
from peewee import Model, SqliteDatabase
from wunderlist.util import workflow

db = SqliteDatabase(workflow().datadir + '/wunderlist.db', threadlocals=True)

class BaseModel(Model):

	@classmethod
	def _api2model(cls, data):
		fields = cls._meta.fields

		# Map relationships, e.g. from user_id to user
		for (k,v) in fields.iteritems():
			if k.endswith('_id'):
				fields[k[:-3]] = v

		return {k:v for (k,v) in data.iteritems() if k in fields}

	@classmethod
	def sync(cls):
		pass

	@classmethod
	def _perform_updates(cls, model_instances, update_items):
		# Map of id to the normalized item
		update_items = { item['id']:cls._api2model(item) for item in update_items }

		for instance in model_instances:
			if not instance:
				continue
			if instance.id in update_items:
示例#35
0
def route(args):
    handler = None
    command = []
    command_string = ''
    action = 'none'

    # Read the stored query, which will correspond to the user's alfred query
    # as of the very latest keystroke. This may be different than the query
    # when this script was launched due to the startup latency.
    if args[0] == '--stored-query':
        query_file = workflow().workflowfile('.query')
        with open(query_file, 'r') as f:
            command_string = workflow().decode(f.read())
        os.remove(query_file)
    # Otherwise take the command from the first command line argument
    elif args:
        command_string = args[0]

    command_string = re.sub(COMMAND_PATTERN, '', command_string)
    command = re.split(r' +', command_string)

    if command:
        action = re.sub(ACTION_PATTERN, '', command[0]) or 'none'

    if 'about'.find(action) == 0:
        from wunderlist.handlers import about
        handler = about
    elif not is_authorized():
        from wunderlist.handlers import login
        handler = login
    elif 'list'.find(action) == 0:
        from wunderlist.handlers import lists
        handler = lists
    elif 'task'.find(action) == 0:
        from wunderlist.handlers import task
        handler = task
    elif 'search'.find(action) == 0:
        from wunderlist.handlers import search
        handler = search
    elif 'due'.find(action) == 0:
        from wunderlist.handlers import due
        handler = due
    elif 'upcoming'.find(action) == 0:
        from wunderlist.handlers import upcoming
        handler = upcoming
    elif 'logout'.find(action) == 0:
        from wunderlist.handlers import logout
        handler = logout
    elif 'pref'.find(action) == 0:
        from wunderlist.handlers import preferences
        handler = preferences
    # If the command starts with a space (no special keywords), the workflow
    # creates a new task
    elif not command_string:
        from wunderlist.handlers import welcome
        handler = welcome
    else:
        from wunderlist.handlers import new_task
        handler = new_task

    if handler:
        if '--commit' in args:
            modifier = re.search(r'--(alt|cmd|ctrl|fn)\b', ' '.join(args))

            if modifier:
                modifier = modifier.group(1)

            handler.commit(command, modifier)
        else:
            handler.filter(command)

            if workflow().update_available:
                update_data = workflow().cached_data(
                    '__workflow_update_status', max_age=0)

                if update_data.get('version') != '0.7.0':
                    workflow().add_item(
                        'An update is available!',
                        'Update the Wunderlist workflow from version 0.7.0 to %s'
                        % update_data.get('version'),
                        arg='-about update',
                        valid=True,
                        icon=icons.DOWNLOAD)

            workflow().send_feedback()
    def _set(self, key, value):
        if self._data.get('key') != value:
            self._data[key] = value

            workflow().store_data('prefs', self._data)
 def prerelease_channel(self, prerelease_channel):
     workflow().settings[PRERELEASES_KEY] = prerelease_channel
示例#38
0
def commit(args, modifier=None):
    auth.deauthorize()
    util.workflow().clear_data()
    util.workflow().clear_cache()

    print 'You are now logged out'
 def prerelease_channel(self):
     return workflow().settings.get(PRERELEASES_KEY, False)
示例#40
0
文件: auth.py 项目: amatiasq/dotfiles
def oauth_token():
    try:
        return workflow().get_password(config.KC_OAUTH_TOKEN)
    except PasswordNotFound:
        return None
#!/usr/bin/python
# encoding: utf-8

import sys, os

sys.path.insert(1, os.path.dirname(__file__))

from wunderlist.handlers.route import route
from wunderlist.util import workflow

def main(wf):
	route(wf.args)

if __name__ == '__main__':
	wf = workflow()
	sys.exit(wf.run(main))
示例#42
0
#!/usr/bin/python
# encoding: utf-8

import logging
from logging.config import fileConfig
import sys

fileConfig('logging_config.ini')

from wunderlist.handlers.route import route
from wunderlist.util import workflow

log = logging.getLogger('wunderlist')

def main(wf):
    route(wf.args)
    log.info('Workflow response complete')

if __name__ == '__main__':
    wf = workflow()
    sys.exit(wf.run(main, text_errors='--commit' in wf.args))
示例#43
0
 def current_prefs(cls):
     if not cls._current_prefs:
         cls._current_prefs = Preferences(workflow().stored_data('prefs'))
     if not cls._current_prefs:
         cls._current_prefs = Preferences({})
     return cls._current_prefs
def oauth_state():
    try:
        return workflow().get_password(config.KC_OAUTH_STATE)
    except PasswordNotFound:
        return None
示例#45
0
def commit(args, modifier=None):
    prefs = Preferences.current_prefs()
    relaunch_command = '-pref'

    if '--alfred' in args:
        relaunch_command = ' '.join(args[args.index('--alfred') + 1:])

    if 'sync' in args:
        from wunderlist.sync import sync
        sync('background' in args)

        relaunch_command = None
    elif 'show_completed_tasks' in args:
        prefs.show_completed_tasks = not prefs.show_completed_tasks

        if prefs.show_completed_tasks:
            print 'Completed tasks are now visible in the workflow'
        else:
            print 'Completed tasks will not be visible in the workflow'
    elif 'default_list' in args:
        default_list_id = None
        lists = workflow().stored_data('lists')

        if len(args) > 2:
            default_list_id = int(args[2])

        prefs.default_list_id = default_list_id

        if default_list_id:
            default_list_name = next(
                (l['title'] for l in lists if l['id'] == default_list_id),
                'Inbox')
            print 'Tasks will be added to your %s list by default' % default_list_name
        else:
            print 'Tasks will be added to the Inbox by default'
    elif 'explicit_keywords' in args:
        prefs.explicit_keywords = not prefs.explicit_keywords

        if prefs.explicit_keywords:
            print 'Remember to use the "due" keyword'
        else:
            print 'Implicit due dates enabled (e.g. "Recycling tomorrow")'
    elif 'reminder' in args:
        reminder_time = _parse_time(' '.join(args))

        if reminder_time is not None:
            prefs.reminder_time = reminder_time

            print 'Reminders will now default to %s' % format_time(
                reminder_time, 'short')
    elif 'reminder_today' in args:
        reminder_today_offset = None

        if not 'disabled' in args:
            reminder_today_offset = _parse_time(' '.join(args))

        prefs.reminder_today_offset = reminder_today_offset

        print 'The offset for current-day reminders is now %s' % _format_time_offset(
            reminder_today_offset)
    elif 'automatic_reminders' in args:
        prefs.automatic_reminders = not prefs.automatic_reminders

        if prefs.automatic_reminders:
            print 'A reminder will automatically be set for due tasks'
        else:
            print 'A reminder will not be added automatically'
    elif 'retheme' in args:
        prefs.icon_theme = 'light' if icons.icon_theme() == 'dark' else 'dark'

        print 'The workflow is now using the %s icon theme' % (
            prefs.icon_theme)
    elif 'prerelease_channel' in args:

        prefs.prerelease_channel = not prefs.prerelease_channel

        # Update the workflow settings and reverify the update data
        workflow().check_update(True)

        if prefs.prerelease_channel:
            print 'The workflow will prompt you to update to experimental pre-releases'
        else:
            print 'The workflow will only prompt you to update to final releases'

    if relaunch_command:
        relaunch_alfred(relaunch_command)
示例#46
0
def filter(args):
    workflow().add_item('New task...',
                        'Begin typing to add a new task',
                        autocomplete=' ',
                        icon=icons.TASK_COMPLETED)

    workflow().add_item('Due today',
                        'Due and overdue tasks',
                        autocomplete='-due ',
                        icon=icons.TODAY)

    workflow().add_item('Upcoming',
                        'Tasks due soon',
                        autocomplete='-upcoming ',
                        icon=icons.UPCOMING)

    workflow().add_item('Find and update tasks',
                        'Search or browse by list',
                        autocomplete='-search ',
                        icon=icons.SEARCH)

    workflow().add_item('New list', autocomplete='-list ', icon=icons.LIST_NEW)

    workflow().add_item('Preferences',
                        autocomplete='-pref ',
                        icon=icons.PREFERENCES)

    workflow().add_item('About',
                        'Learn about the workflow and get support',
                        autocomplete='-about ',
                        icon=icons.INFO)
示例#47
0
def route(args):
    handler = None
    command = []
    command_string = ''
    action = 'none'

    # Read the stored query, which will correspond to the user's alfred query
    # as of the very latest keystroke. This may be different than the query
    # when this script was launched due to the startup latency.
    if args[0] == '--stored-query':
        query_file = workflow().workflowfile('.query')
        with open(query_file, 'r') as f:
            command_string = workflow().decode(f.read())
        os.remove(query_file)
    # Otherwise take the command from the first command line argument
    elif args:
        command_string = args[0]

    command_string = re.sub(COMMAND_PATTERN, '', command_string)
    command = re.split(r' +', command_string)

    if command:
        action = re.sub(ACTION_PATTERN, '', command[0]) or 'none'

    if 'about'.find(action) == 0:
        from wunderlist.handlers import about
        handler = about
    elif not is_authorized():
        from wunderlist.handlers import login
        handler = login
    elif 'list'.find(action) == 0:
        from wunderlist.handlers import lists
        handler = lists
    elif 'task'.find(action) == 0:
        from wunderlist.handlers import task
        handler = task
    elif 'search'.find(action) == 0:
        from wunderlist.handlers import search
        handler = search
    elif 'due'.find(action) == 0:
        from wunderlist.handlers import due
        handler = due
    elif 'upcoming'.find(action) == 0:
        from wunderlist.handlers import upcoming
        handler = upcoming
    elif 'logout'.find(action) == 0:
        from wunderlist.handlers import logout
        handler = logout
    elif 'pref'.find(action) == 0:
        from wunderlist.handlers import preferences
        handler = preferences
    # If the command starts with a space (no special keywords), the workflow
    # creates a new task
    elif not command_string:
        from wunderlist.handlers import welcome
        handler = welcome
    else:
        from wunderlist.handlers import new_task
        handler = new_task

    if handler:
        if '--commit' in args:
            modifier = re.search(r'--(alt|cmd|ctrl|fn)\b', ' '.join(args))

            if modifier:
                modifier = modifier.group(1)

            handler.commit(command, modifier)
        else:
            handler.filter(command)

            if workflow().update_available:
                update_data = workflow().cached_data('__workflow_update_status', max_age=0)

                if update_data.get('version') != '0.7.0':
                    workflow().add_item('An update is available!', 'Update the Wunderlist workflow from version 0.7.0 to %s' % update_data.get('version'), arg='-about update', valid=True, icon=icons.DOWNLOAD)

            workflow().send_feedback()
示例#48
0
def filter(args):
    prefs = Preferences.current_prefs()

    if 'reminder' in args:
        reminder_time = _parse_time(' '.join(args))

        if reminder_time is not None:
            workflow().add_item('Change default reminder time',
                                u'⏰ %s' % format_time(reminder_time, 'short'),
                                arg=' '.join(args),
                                valid=True,
                                icon=icons.REMINDER)
        else:
            workflow().add_item(
                'Type a new reminder time',
                'Date offsets like the morning before the due date are not supported yet',
                valid=False,
                icon=icons.REMINDER)

        workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK)
    elif 'reminder_today' in args:
        reminder_today_offset = _parse_time(' '.join(args))

        if reminder_today_offset is not None:
            workflow().add_item('Set a custom reminder offset',
                                u'⏰ now + %s' %
                                _format_time_offset(reminder_today_offset),
                                arg=' '.join(args),
                                valid=True,
                                icon=icons.REMINDER)
        else:
            workflow().add_item('Type a custom reminder offset',
                                'Use the formats hh:mm or 2h 5m',
                                valid=False,
                                icon=icons.REMINDER)

        workflow().add_item('30 minutes',
                            arg='-pref reminder_today 30m',
                            valid=True,
                            icon=icons.REMINDER)

        workflow().add_item('1 hour',
                            '(default)',
                            arg='-pref reminder_today 1h',
                            valid=True,
                            icon=icons.REMINDER)

        workflow().add_item('90 minutes',
                            arg='-pref reminder_today 90m',
                            valid=True,
                            icon=icons.REMINDER)

        workflow().add_item(
            'Always use the default reminder time',
            'Avoids adjusting the reminder based on the current date',
            arg='-pref reminder_today disabled',
            valid=True,
            icon=icons.CANCEL)

        workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK)
    elif 'default_list' in args:
        lists = workflow().stored_data('lists')
        matching_lists = lists

        if len(args) > 2:
            list_query = ' '.join(args[2:])
            if list_query:
                matching_lists = workflow().filter(
                    list_query,
                    lists,
                    lambda l: l['title'],
                    # Ignore MATCH_ALLCHARS which is expensive and inaccurate
                    match_on=MATCH_ALL ^ MATCH_ALLCHARS)

        for i, l in enumerate(matching_lists):
            if i == 1:
                workflow().add_item(
                    'Most recently used list',
                    'Default to the last list to which a task was added',
                    arg='-pref default_list %d' % DEFAULT_LIST_MOST_RECENT,
                    valid=True,
                    icon=icons.RECURRENCE)
            icon = icons.INBOX if l['list_type'] == 'inbox' else icons.LIST
            workflow().add_item(l['title'],
                                arg='-pref default_list %s' % l['id'],
                                valid=True,
                                icon=icon)

        workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK)
    else:
        current_user = None
        lists = workflow().stored_data('lists')
        default_list_name = 'Inbox'

        try:
            current_user = User.get()
        except User.DoesNotExist:
            pass
        except OperationalError:
            from wunderlist.sync import background_sync
            background_sync()

        if prefs.default_list_id == DEFAULT_LIST_MOST_RECENT:
            default_list_name = 'Most recent list'
        else:
            default_list_id = prefs.default_list_id
            default_list_name = next(
                (l['title'] for l in lists if l['id'] == default_list_id),
                'Inbox')

        if current_user and current_user.name:
            workflow().add_item('Sign out',
                                'You are logged in as ' + current_user.name,
                                autocomplete='-logout',
                                icon=icons.CANCEL)

        workflow().add_item('Show completed tasks',
                            'Includes completed tasks in search results',
                            arg='-pref show_completed_tasks',
                            valid=True,
                            icon=icons.TASK_COMPLETED
                            if prefs.show_completed_tasks else icons.TASK)

        workflow().add_item(
            'Default reminder time',
            u'⏰ %s    Reminders without a specific time will be set to this time'
            % format_time(prefs.reminder_time, 'short'),
            autocomplete='-pref reminder ',
            icon=icons.REMINDER)

        workflow().add_item(
            'Default reminder when due today',
            u'⏰ %s    Default reminder time for tasks due today is %s' %
            (_format_time_offset(prefs.reminder_today_offset),
             'relative to the current time' if prefs.reminder_today_offset else
             'always %s' % format_time(prefs.reminder_time, 'short')),
            autocomplete='-pref reminder_today ',
            icon=icons.REMINDER)

        workflow().add_item(
            'Default list',
            u'%s    Change the default list when creating new tasks' %
            default_list_name,
            autocomplete='-pref default_list ',
            icon=icons.LIST)

        workflow().add_item(
            'Automatically set a reminder on the due date',
            u'Sets a default reminder for tasks with a due date.',
            arg='-pref automatic_reminders',
            valid=True,
            icon=icons.TASK_COMPLETED
            if prefs.automatic_reminders else icons.TASK)

        workflow().add_item(
            'Require explicit due keyword',
            'Requires the due keyword to avoid accidental due date extraction',
            arg='-pref explicit_keywords',
            valid=True,
            icon=icons.TASK_COMPLETED
            if prefs.explicit_keywords else icons.TASK)

        workflow().add_item(
            'Check for experimental updates to this workflow',
            'The workflow automatically checks for updates; enable this to include pre-releases',
            arg=':pref prerelease_channel',
            valid=True,
            icon=icons.TASK_COMPLETED
            if prefs.prerelease_channel else icons.TASK)

        workflow().add_item(
            'Force sync',
            'The workflow syncs automatically, but feel free to be forcible.',
            arg='-pref sync',
            valid=True,
            icon=icons.SYNC)

        workflow().add_item('Switch theme',
                            'Toggle between light and dark icons',
                            arg='-pref retheme',
                            valid=True,
                            icon=icons.PAINTBRUSH)

        workflow().add_item('Main menu', autocomplete='', icon=icons.BACK)
示例#49
0
def filter(args):
    wf = workflow()
    prefs = Preferences.current_prefs()
    command = args[1] if len(args) > 1 else None

    # Show sort options
    if command == 'sort':
        for i, order_info in enumerate(_due_orders):
            wf.add_item(order_info['title'],
                        order_info['subtitle'],
                        arg='-due sort %d' % (i + 1),
                        valid=True,
                        icon=icons.RADIO_SELECTED if order_info['due_order']
                        == prefs.due_order else icons.RADIO)

        wf.add_item(
            'Highlight skipped recurring tasks',
            'Hoists recurring tasks that have been missed multiple times over to the top',
            arg='-due sort toggle-skipped',
            valid=True,
            icon=icons.CHECKBOX_SELECTED
            if prefs.hoist_skipped_tasks else icons.CHECKBOX)

        wf.add_item('Back', autocomplete='-due ', icon=icons.BACK)

        return

    # Force a sync if not done recently or wait on the current sync
    if not prefs.last_sync or \
       datetime.now() - prefs.last_sync > timedelta(seconds=30) or \
       is_running('sync'):
        sync()

    conditions = True

    # Build task title query based on the args
    for arg in args[1:]:
        if len(arg) > 1:
            conditions = conditions & (Task.title.contains(arg)
                                       | List.title.contains(arg))

    if conditions is None:
        conditions = True

    tasks = Task.select().join(
        List).where(Task.completed_at.is_null()
                    & (Task.due_date < date.today() + timedelta(days=1))
                    & Task.list.is_null(False) & conditions)

    # Sort the tasks according to user preference
    for key in prefs.due_order:
        order = 'asc'
        field = None
        if key[0] == '-':
            order = 'desc'
            key = key[1:]

        if key == 'due_date':
            field = Task.due_date
        elif key == 'list.order':
            field = List.order
        elif key == 'order':
            field = Task.order

        if field:
            if order == 'asc':
                tasks = tasks.order_by(field.asc())
            else:
                tasks = tasks.order_by(field.desc())

    try:
        if prefs.hoist_skipped_tasks:
            tasks = sorted(tasks, key=lambda t: -t.overdue_times)

        for t in tasks:
            wf.add_item(
                u'%s – %s' % (t.list_title, t.title),
                t.subtitle(),
                autocomplete='-task %s ' % t.id,
                icon=icons.TASK_COMPLETED if t.completed else icons.TASK)
    except OperationalError:
        background_sync()

    wf.add_item(u'Sort order',
                'Change the display order of due tasks',
                autocomplete='-due sort',
                icon=icons.SORT)

    wf.add_item('Main menu', autocomplete='', icon=icons.BACK)

    # Make sure tasks stay up-to-date
    background_sync_if_necessary(seconds=2)
    def _parse(self):
        cls = type(self)
        phrase = self.phrase
        cal = parsedatetime_calendar()
        wf = workflow()
        lists = wf.stored_data('lists')
        prefs = Preferences.current_prefs()
        ignore_due_date = False

        match = re.search(HASHTAG_PROMPT_PATTERN, phrase)
        if match:
            self.hashtag_prompt = match.group(1)
            self.has_hashtag_prompt = True

        match = re.search(SLASHES_PATTERN, phrase)
        if match:
            self._note_phrase = match.group(1) + match.group(2)
            self.note = re.sub(
                WHITESPACE_CLEANUP_PATTERN, ' ', match.group(2)).strip()
            phrase = phrase[:match.start()] + phrase[match.end():]

        match = re.search(STAR_PATTERN, phrase)
        if match:
            self.starred = True
            self._starred_phrase = match.group()
            phrase = phrase[:match.start()] + phrase[match.end():]

        match = re.search(NOT_DUE_PATTERN, phrase)
        if match:
            ignore_due_date = True
            phrase = phrase[:match.start()] + phrase[match.end():]

        match = re.search(LIST_TITLE_PATTERN, phrase)
        if lists and match:
            if match.group(1):
                matching_lists = wf.filter(
                    match.group(1),
                    lists,
                    lambda l: l['title'],
                    # Ignore MATCH_ALLCHARS which is expensive and inaccurate
                    match_on=MATCH_ALL ^ MATCH_ALLCHARS
                )

                # Take the first match as the desired list
                if matching_lists:
                    self.list_id = matching_lists[0]['id']
                    self.list_title = matching_lists[0]['title']
            # The list name was empty
            else:
                self.has_list_prompt = True

            if self.list_title or self.has_list_prompt:
                self._list_phrase = match.group()
                phrase = phrase[:match.start()] + phrase[match.end():]

        # Parse and remove the recurrence phrase first so that any dates do
        # not interfere with the due date
        match = re.search(RECURRENCE_PATTERN, phrase)
        if match:
            type_phrase = match.group(2) if match.group(2) else match.group(3)
            if type_phrase:
                # Look up the recurrence type based on the first letter of the
                # work or abbreviation used in the phrase
                self.recurrence_type = RECURRENCE_TYPES[type_phrase[0].lower()]
                self.recurrence_count = int(match.group(1) or 1)
            else:
                match = re.search(RECURRENCE_BY_DATE_PATTERN, phrase)
                if match:
                    recurrence_phrase = match.group()
                    dates = cal.nlp(match.group(1), version=2)

                    if dates:
                        # Only remove the first date following `every`
                        datetime_info = dates[0]
                        # Set due_date if a datetime was found and it is not time only
                        if datetime_info[1].hasDate:
                            self.due_date = datetime_info[0].date()
                            date_expression = datetime_info[4]

                            # FIXME: This logic could be improved to better
                            # differentiate between week and year expressions

                            # If the date expression is only one word and the next
                            # due date is less than one week from now, set a
                            # weekly recurrence, e.g. every Tuesday
                            if len(date_expression.split(' ')) == 1 and self.due_date < date.today() + timedelta(days=8):
                                self.recurrence_count = 1
                                self.recurrence_type = 'week'
                            # Otherwise expect a multi-word value like a date,
                            # e.g. every May 17
                            else:
                                self.recurrence_count = 1
                                self.recurrence_type = 'year'

                            self.has_recurrence_prompt = False

                            # Pull in any words between the `due` keyword and the
                            # actual date text
                            date_pattern = re.escape(date_expression)
                            date_pattern = r'.*?' + date_pattern

                            # Prepare to set the recurrence phrase below
                            match = re.search(date_pattern, recurrence_phrase)

            # This is just the "every" keyword with no date following
            if not self.recurrence_type:
                self.has_recurrence_prompt = True

            self._recurrence_phrase = match.group()
            phrase = phrase.replace(self._recurrence_phrase, '', 1)


        reminder_info = None
        match = re.search(REMINDER_PATTERN, phrase)
        if match:
            datetimes = cal.nlp(match.group(2), version=2)

            # If there is at least one date immediately following the reminder
            # phrase use it as the reminder date
            if datetimes and datetimes[0][2] == 0:
                # Only remove the first date following the keyword
                reminder_info = datetimes[0]

                self._reminder_phrase = match.group(1) + reminder_info[4]
                phrase = phrase.replace(self._reminder_phrase, '', 1)
            # Otherwise if there is just a reminder phrase, set the reminder
            # to the default time on the date due
            else:
                # There is no text following the reminder phrase, prompt for a reminder
                if not match.group(2):
                    self.has_reminder_prompt = True
                self._reminder_phrase = match.group(1)

                # Careful, this might just be the letter "r" so rather than
                # replacing it is better to strip out by index
                phrase = phrase[:match.start(1)] + phrase[match.end(1):]


        due_keyword = None
        potential_date_phrase = None
        if not ignore_due_date:
            match = re.search(DUE_PATTERN, phrase)
            # Search for the due date only following the `due` keyword
            if match:
                due_keyword = match.group(1)

                if match.group(2):
                    potential_date_phrase = match.group(2)
            # Otherwise find a due date anywhere in the phrase
            elif not prefs.explicit_keywords:
                potential_date_phrase = phrase

        if potential_date_phrase:
            dates = cal.nlp(potential_date_phrase, version=2)

            if dates:
                # Only remove the first date following `due`
                datetime_info = dates[0]
                # Set due_date if a datetime was found and it is not time only
                if datetime_info[1].hasDate:
                    self.due_date = datetime_info[0].date()
                elif datetime_info[1].hasTime and not self.due_date:
                    self.due_date = date.today()

                if self.due_date:
                    # Pull in any words between the `due` keyword and the
                    # actual date text
                    date_pattern = re.escape(datetime_info[4])

                    if due_keyword:
                        date_pattern = re.escape(due_keyword) + r'.*?' + date_pattern

                    due_date_phrase_match = re.search(date_pattern, phrase)

                    if due_date_phrase_match:
                        self._due_date_phrase = due_date_phrase_match.group()
                        phrase = phrase.replace(self._due_date_phrase, '', 1)

                    # If the due date specifies a time, set it as the reminder
                    if datetime_info[1].hasTime:
                        if datetime_info[1].hasDate:
                            self.reminder_date = datetime_info[0]
                        elif self.due_date:
                            self.reminder_date = datetime.combine(self.due_date, datetime_info[0].time())
                # Just a time component
                else:
                    due_keyword = None
            # No dates in the phrase
            else:
                due_keyword = None

        # The word due was not followed by a date
        if due_keyword and not self._due_date_phrase:
            self.has_due_date_prompt = True
            self._due_date_phrase = match.group(1)

            # Avoid accidentally replacing "due" inside words elsewhere in the
            # string
            phrase = phrase[:match.start(1)] + phrase[match.end(1):]

        if self.recurrence_type and not self.due_date:
            self.due_date = date.today()

        if self._reminder_phrase:
            # If a due date is set, a time-only reminder is relative to that
            # date; otherwise if there is no due date it is relative to today
            reference_date = self.due_date if self.due_date else date.today()

            if reminder_info:
                (dt, datetime_context, _, _, _) = reminder_info

                # Date and time; use as-is
                if datetime_context.hasTime and datetime_context.hasDate:
                    self.reminder_date = dt
                # Time only; set the reminder on the due day
                elif datetime_context.hasTime:
                    self.reminder_date = cls.reminder_date_combine(reference_date, dt)
                # Date only; set the default reminder time on that day
                elif datetime_context.hasDate:
                    self.reminder_date = cls.reminder_date_combine(dt)

            else:
                self.reminder_date = cls.reminder_date_combine(reference_date)

        # Look for a list title at the end of the remaining phrase, like
        # "in list Office"
        if not self.list_title:
            matches = re.finditer(INFIX_LIST_KEYWORD_PATTERN, phrase)
            for match in matches:
                subphrase = phrase[match.end():]

                # Just a couple characters are too likely to result in a false
                # positive, but allow it if the letters are capitalized
                if len(subphrase) > 2 or subphrase == subphrase.upper():
                    matching_lists = wf.filter(
                        subphrase,
                        lists,
                        lambda l: l['title'],
                        # Ignore MATCH_ALLCHARS which is expensive and inaccurate
                        match_on=MATCH_ALL ^ MATCH_ALLCHARS
                    )

                    # Take the first match as the desired list
                    if matching_lists:
                        self.list_id = matching_lists[0]['id']
                        self.list_title = matching_lists[0]['title']
                        self._list_phrase = match.group() + subphrase
                        phrase = phrase[:match.start()]
                        break

        # No list parsed, assign to inbox
        if not self.list_title:
            if prefs.default_list_id and lists:
                if prefs.default_list_id == DEFAULT_LIST_MOST_RECENT:
                    self.list_id = prefs.last_list_id
                else:
                    self.list_id = prefs.default_list_id
                default_list = next((l for l in lists if l['id'] == self.list_id), None)
                if default_list:
                    self.list_title = default_list['title']

            if not self.list_title:
                if lists:
                    inbox = lists[0]
                    self.list_id = inbox['id']
                    self.list_title = inbox['title']
                else:
                    self.list_id = 0
                    self.list_title = 'Inbox'

        # Set an automatic reminder when there is a due date without a
        # specified reminder
        if self.due_date and not self.reminder_date and prefs.automatic_reminders:
            self.reminder_date = cls.reminder_date_combine(self.due_date)

        # Condense extra whitespace remaining in the task title after parsing
        self.title = re.sub(WHITESPACE_CLEANUP_PATTERN, ' ', phrase).strip()
def deauthorize():
    try:
        workflow().delete_password(config.KC_OAUTH_TOKEN)
    except PasswordNotFound:
        pass
示例#52
0
文件: auth.py 项目: amatiasq/dotfiles
def deauthorize():
    try:
        workflow().delete_password(config.KC_OAUTH_TOKEN)
    except PasswordNotFound:
        pass
示例#53
0
def filter(args):
    getting_help = False

    if len(args) > 0:
        action = re.sub(ACTION_PATTERN, '', args[0])
        getting_help = action and 'help'.find(action) == 0

    if not getting_help:
        workflow().add_item(
            'Please log in',
            'Authorize Alfred Wunderlist Workflow to use your Wunderlist account',
            valid=True, icon=icons.ACCOUNT
        )

    # If the auth process has started, allow user to paste a key manually
    if getting_help:
        workflow().add_item(
            'A "localhost" page appeared in my web browser',
            u'Paste the full link from your browser above then press return, wl:help http://localhost:6200/…',
            arg=' '.join(args), valid=True, icon=icons.LINK
        )
        workflow().add_item(
            'I need to log in to a different account',
            'Go to wunderlist.com in your browser and sign out of your account first',
            arg='-about wunderlist', valid=True, icon=icons.ACCOUNT
        )
        workflow().add_item(
            'Other issues?',
            'See outstanding issues and report your own bugs or feedback',
            arg='-about issues', valid=True, icon=icons.HELP
        )
    else:
        workflow().add_item(
            'Having trouble?',
            autocomplete='-help ', valid=False, icon=icons.HELP
        )

    if not getting_help:
        workflow().add_item(
            'About',
            'Learn about the workflow and get support',
            autocomplete='-about ',
            icon=icons.INFO
        )
def filter(args):
    query = ' '.join(args[1:])
    wf = workflow()
    prefs = Preferences.current_prefs()
    matching_hashtags = []

    if not query:
        wf.add_item('Begin typing to search tasks', '', icon=icons.SEARCH)

    hashtag_match = re.search(_hashtag_prompt_pattern, query)
    if hashtag_match:
        from wunderlist.models.hashtag import Hashtag

        hashtag_prompt = hashtag_match.group().lower()
        hashtags = Hashtag.select().where(
            Hashtag.id.contains(hashtag_prompt)).order_by(
                fn.Lower(Hashtag.tag).asc())

        for hashtag in hashtags:
            # If there is an exact match, do not show hashtags
            if hashtag.id == hashtag_prompt:
                matching_hashtags = []
                break

            matching_hashtags.append(hashtag)

    # Show hashtag prompt if there is more than one matching hashtag or the
    # hashtag being typed does not exactly match the single matching hashtag
    if len(matching_hashtags) > 0:
        for hashtag in matching_hashtags:
            wf.add_item(hashtag.tag[1:],
                        '',
                        autocomplete=u'-search %s%s ' %
                        (query[:hashtag_match.start()], hashtag.tag),
                        icon=icons.HASHTAG)

    else:
        conditions = True
        lists = workflow().stored_data('lists')
        matching_lists = None
        query = ' '.join(args[1:]).strip()
        list_query = None

        # Show all lists on the main search screen
        if not query:
            matching_lists = lists
        # Filter lists when colon is used
        if ':' in query:
            matching_lists = lists
            components = re.split(r':\s*', query, 1)
            list_query = components[0]
            if list_query:
                matching_lists = workflow().filter(
                    list_query,
                    lists if lists else [],
                    lambda l: l['title'],
                    # Ignore MATCH_ALLCHARS which is expensive and inaccurate
                    match_on=MATCH_ALL ^ MATCH_ALLCHARS)

                # If no matching list search against all tasks
                if matching_lists:
                    query = components[1] if len(components) > 1 else ''

                # If there is a list exactly matching the query ignore
                # anything else. This takes care of lists that are substrings
                # of other lists
                if len(matching_lists) > 1:
                    for l in matching_lists:
                        if l['title'].lower() == list_query.lower():
                            matching_lists = [l]
                            break

        if matching_lists:
            if not list_query:
                wf.add_item('Browse by hashtag',
                            autocomplete='-search #',
                            icon=icons.HASHTAG)

            if len(matching_lists) > 1:
                for l in matching_lists:
                    icon = icons.INBOX if l[
                        'list_type'] == 'inbox' else icons.LIST
                    wf.add_item(l['title'],
                                autocomplete='-search %s: ' % l['title'],
                                icon=icon)
            else:
                conditions = conditions & (Task.list
                                           == matching_lists[0]['id'])

        if not matching_lists or len(matching_lists) <= 1:
            for arg in query.split(' '):
                if len(arg) > 1:
                    conditions = conditions & (Task.title.contains(arg)
                                               | List.title.contains(arg))

            if conditions:
                if not prefs.show_completed_tasks:
                    conditions = Task.completed_at.is_null() & conditions

                tasks = Task.select().where(
                    Task.list.is_null(False) & conditions)

                # Default Wunderlist sort order reversed to show newest first
                tasks = tasks.join(List).order_by(Task.order.desc(),
                                                  List.order.asc())

                # Avoid excessive results
                tasks = tasks.limit(50)

                try:
                    for t in tasks:
                        wf.add_item(u'%s – %s' % (t.list_title, t.title),
                                    t.subtitle(),
                                    autocomplete='-task %s  ' % t.id,
                                    icon=icons.TASK_COMPLETED
                                    if t.completed else icons.TASK)
                except OperationalError:
                    background_sync()

            if prefs.show_completed_tasks:
                wf.add_item('Hide completed tasks',
                            arg='-pref show_completed_tasks --alfred %s' %
                            ' '.join(args),
                            valid=True,
                            icon=icons.HIDDEN)
            else:
                wf.add_item('Show completed tasks',
                            arg='-pref show_completed_tasks --alfred %s' %
                            ' '.join(args),
                            valid=True,
                            icon=icons.VISIBLE)

        wf.add_item('New search', autocomplete='-search ', icon=icons.CANCEL)
        wf.add_item('Main menu', autocomplete='', icon=icons.BACK)

        # Make sure tasks are up-to-date while searching
        background_sync()
 def current_prefs(cls):
     if not cls._current_prefs:
         cls._current_prefs = Preferences(workflow().stored_data('prefs'))
     if not cls._current_prefs:
         cls._current_prefs = Preferences({})
     return cls._current_prefs
示例#56
0
文件: auth.py 项目: amatiasq/dotfiles
def oauth_state():
    try:
        return workflow().get_password(config.KC_OAUTH_STATE)
    except PasswordNotFound:
        return None
示例#57
0
def filter(args):
    wf = workflow()
    prefs = Preferences.current_prefs()
    command = args[1] if len(args) > 1 else None
    duration_info = _duration_info(prefs.upcoming_duration)

    if command == 'duration':
        selected_duration = prefs.upcoming_duration

        # Apply selected duration option
        if len(args) > 2:
            try:
                selected_duration = int(args[2])
            except:
                pass

        duration_info = _duration_info(selected_duration)

        if 'custom' in duration_info:
            wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO)

        for duration_info in _durations:
            wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO)

        wf.add_item('Back', autocomplete='-upcoming ', icon=icons.BACK)

        return

    # Force a sync if not done recently or join if already running
    if not prefs.last_sync or \
       datetime.now() - prefs.last_sync > timedelta(seconds=30) or \
       is_running('sync'):
        sync()

    wf.add_item(duration_info['label'], subtitle='Change the duration for upcoming tasks', autocomplete='-upcoming duration ', icon=icons.UPCOMING)

    conditions = True

    # Build task title query based on the args
    for arg in args[1:]:
        if len(arg) > 1:
            conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg))

    if conditions is None:
        conditions = True

    tasks = Task.select().join(List).where(
        Task.completed_at.is_null() &
        (Task.due_date < date.today() + timedelta(days=duration_info['days'] + 1)) &
        (Task.due_date > date.today() + timedelta(days=1)) &
        Task.list.is_null(False) &
        conditions
    )\
        .join(Reminder, JOIN.LEFT_OUTER, on=Reminder.task == Task.id)\
        .order_by(Task.due_date.asc(), Reminder.date.asc(), Task.order.asc())

    try:
        for t in tasks:
            wf.add_item(u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK)
    except OperationalError:
        background_sync()

    wf.add_item('Main menu', autocomplete='', icon=icons.BACK)

    # Make sure tasks stay up-to-date
    background_sync_if_necessary(seconds=2)