Skip to content

Commit

Permalink
Began working on a rewrite in Python using the official Wunderlist API.
Browse files Browse the repository at this point in the history
  • Loading branch information
idpaterson committed Feb 15, 2015
1 parent 4f13880 commit 3781c7b
Show file tree
Hide file tree
Showing 24 changed files with 637 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
*.pyc
14 changes: 14 additions & 0 deletions alfred-wunderlist-workflow.py
@@ -0,0 +1,14 @@
#!/usr/bin/python
# encoding: utf-8

import sys

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))
Binary file added icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 134 additions & 0 deletions info.plist
@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>bundleid</key>
<string>com.ipaterson.alfred.wunderlist</string>
<key>connections</key>
<dict>
<key>0F2D229C-18BA-4E40-A81D-D796A6E159BC</key>
<array>
<dict>
<key>destinationuid</key>
<string>E0AE4F8B-253B-4EFD-B568-E9A2A46AA0C7</string>
<key>modifiers</key>
<integer>0</integer>
<key>modifiersubtext</key>
<string></string>
</dict>
<dict>
<key>destinationuid</key>
<string>39540B6D-5AA4-4427-BA63-42256009EE5F</string>
<key>modifiers</key>
<integer>524288</integer>
<key>modifiersubtext</key>
<string></string>
</dict>
</array>
</dict>
<key>createdby</key>
<string>Ian Paterson</string>
<key>description</key>
<string>Create tasks and lists in Wunderlist 2</string>
<key>disabled</key>
<false/>
<key>name</key>
<string>Wunderlist</string>
<key>objects</key>
<array>
<dict>
<key>config</key>
<dict>
<key>argumenttype</key>
<integer>1</integer>
<key>escaping</key>
<integer>102</integer>
<key>keyword</key>
<string>wl</string>
<key>queuedelaycustom</key>
<integer>3</integer>
<key>queuedelayimmediatelyinitially</key>
<false/>
<key>queuedelaymode</key>
<integer>0</integer>
<key>queuemode</key>
<integer>2</integer>
<key>runningsubtext</key>
<string>Preparing workflow</string>
<key>script</key>
<string>/usr/bin/env python alfred-wunderlist-workflow.py {query}</string>
<key>subtext</key>
<string>Type wl to control Wunderlist</string>
<key>title</key>
<string>Wunderlist</string>
<key>type</key>
<integer>0</integer>
<key>withspace</key>
<true/>
</dict>
<key>type</key>
<string>alfred.workflow.input.scriptfilter</string>
<key>uid</key>
<string>0F2D229C-18BA-4E40-A81D-D796A6E159BC</string>
<key>version</key>
<integer>0</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>escaping</key>
<integer>102</integer>
<key>script</key>
<string>/usr/bin/env python alfred-wunderlist-workflow.py --commit {query}</string>
<key>type</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.action.script</string>
<key>uid</key>
<string>E0AE4F8B-253B-4EFD-B568-E9A2A46AA0C7</string>
<key>version</key>
<integer>0</integer>
</dict>
<dict>
<key>config</key>
<dict>
<key>escaping</key>
<integer>102</integer>
<key>script</key>
<string>/usr/bin/env python alfred-wunderlist-workflow.py --commit --alt {query}</string>
<key>type</key>
<integer>0</integer>
</dict>
<key>type</key>
<string>alfred.workflow.action.script</string>
<key>uid</key>
<string>39540B6D-5AA4-4427-BA63-42256009EE5F</string>
<key>version</key>
<integer>0</integer>
</dict>
</array>
<key>readme</key>
<string>Readme</string>
<key>uidata</key>
<dict>
<key>0F2D229C-18BA-4E40-A81D-D796A6E159BC</key>
<dict>
<key>ypos</key>
<real>10</real>
</dict>
<key>39540B6D-5AA4-4427-BA63-42256009EE5F</key>
<dict>
<key>ypos</key>
<real>130</real>
</dict>
<key>E0AE4F8B-253B-4EFD-B568-E9A2A46AA0C7</key>
<dict>
<key>ypos</key>
<real>10</real>
</dict>
</dict>
<key>webaddress</key>
<string>https://github.com/idpaterson</string>
</dict>
</plist>
1 change: 1 addition & 0 deletions requirements.txt
@@ -0,0 +1 @@
Alfred-Workflow==1.11.1
Empty file added wunderlist/__init__.py
Empty file.
Empty file added wunderlist/api/__init__.py
Empty file.
55 changes: 55 additions & 0 deletions wunderlist/api/base.py
@@ -0,0 +1,55 @@
import json
import requests
from wunderlist.auth import oauth_token
from wunderlist import config

def _request_headers():
token = oauth_token()

if token:
return {
'x-access-token': token,
'x-client-id': config.WL_CLIENT_ID,
'content-type': 'application/json'
}
return None

def get(path, params=None):
headers = _request_headers()
return requests.get(
config.WL_API_BASE_URL + '/' + path,
headers=headers,
params=params
)

def post(path, data=None):
headers = _request_headers()
return requests.post(
config.WL_API_BASE_URL + '/' + path,
headers=headers,
data=json.dumps(data)
)

def put(path, data=None):
headers = _request_headers()
return requests.put(
config.WL_API_BASE_URL + '/' + path,
headers=headers,
data=json.dumps(data)
)

def patch(path, data=None):
headers = _request_headers()
return requests.patch(
config.WL_API_BASE_URL + '/' + path,
headers=headers,
data=json.dumps(data)
)

def delete(path, data=None):
headers = _request_headers()
return requests.delete(
config.WL_API_BASE_URL + '/' + path,
headers=headers,
data=json.dumps(data)
)
58 changes: 58 additions & 0 deletions wunderlist/api/lists.py
@@ -0,0 +1,58 @@
import requests
import wunderlist.api.base as api

SMART_LISTS = [
'inbox'
]

def lists(order='display'):
req = api.get('lists')
lists = req.json()

if order == 'display':
positions = list_positions()

def position(list):
if list['list_type'] in SMART_LISTS:
return SMART_LISTS.index(list['list_type'])
elif list['id'] in positions:
return positions.index(list['id']) + len(SMART_LISTS)
else:
return list['id']

lists.sort(key=position)

return lists

def list_positions():
req = api.get('list_positions')
info = req.json()

return info[0]['values']

def list(id, task_counts=False):
req = api.get('lists/' + id)
info = req.json()

# TODO: run this request in parallel
if task_counts:
info['task_counts'] = list_tasks_count(id)

return info

def list_tasks_count(id):
req = api.get('lists/tasks_count', { 'list_id': id })
info = req.json()

return info

def create_list(title):
req = api.post('lists', { 'title': title })
info = req.json()

return info

def delete_list(id, revision):
req = api.delete('lists/' + id, { 'revision': revision })

return req.status_code == requests.codes.no_content
93 changes: 93 additions & 0 deletions wunderlist/api/tasks.py
@@ -0,0 +1,93 @@
import requests
import wunderlist.api.base as api

NO_CHANGE='!nochange!'

def tasks(list_id, order='display', completed=False):
req = api.get('tasks', {
'list_id': int(list_id),
'completed': completed
})
tasks = req.json()

if order == 'display':
positions = task_positions(list_id)

def position(task):
return positions.index(task['id'])

tasks.sort(key=position)

return tasks

def task_positions(list_id):
req = api.get('task_positions', { 'list_id': list_id })
info = req.json()

return info[0]['values']

def task(id):
req = api.get('tasks/' + id)
info = req.json()

return info

def create_task(list_id, title, assignee_id=None, recurrence_type=None, recurrence_count=None, due_date=None, starred=False, completed=False):
params = {
'list_id': int(list_id),
'title': title,
'starred': starred,
'completed': completed
}

if assignee_id:
params['assignee_id'] = int(assignee_id)

if recurrence_type:
params['recurrence_type'] = recurrence_type
params['recurrence_count'] = recurrence_count

if due_date:
params['due_date'] = due_date

req = api.post('tasks', params)
info = req.json()

return info

def update_task(id, revision, title=NO_CHANGE, assignee_id=NO_CHANGE, recurrence_type=NO_CHANGE, recurrence_count=NO_CHANGE, due_date=NO_CHANGE, starred=NO_CHANGE, completed=NO_CHANGE):
params = {}
remove = []
changes = {
'title': title,
'assignee_id': int(assignee_id),
'recurrence_type': recurrence_type,
'recurrence_count': recurrence_count,
'due_date': due_date,
'starred': starred,
'completed': completed
}

for (key, value) in changes.iteritems():
if value is None:
remove.append(key)
elif value != NO_CHANGE:
params[key] = value

if remove:
params['remove'] = remove

if params:
params['revision'] = revision

req = api.patch('tasks/' + id, params)
info = req.json()

return info

return None

def delete_task(id, revision):
req = api.delete('tasks/' + id, { 'revision': revision })

return req.status_code == requests.codes.no_content
7 changes: 7 additions & 0 deletions wunderlist/api/user.py
@@ -0,0 +1,7 @@
import wunderlist.api.base as api

def user():
req = api.get('user')
user = req.json()

return user

0 comments on commit 3781c7b

Please sign in to comment.