Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add files via upload #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: python asana_reminders.py
138 changes: 107 additions & 31 deletions asana_reminders.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,129 @@
###################
# DEFINE LIBRARIES
###################

import base64
from base64 import b64encode
import datetime
import json
import os
import urllib
import urllib2

workspace_id = os.environ['ASANA_WORKSPACE_ID']
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(30)
# GD 2019-01-04: I am using URLLIB here but everyone is recommending switching to REQUESTS. Need to do that!

import urllib.request as urllib
from urllib.request import urlopen
import urllib.parse



###################
# DEFINE VARIABLES
###################

# ASANA_WORKSPACE_ID
# ASANA_API_KEY

workspace_id = 'xxx'
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(45)
yesterday = datetime.datetime.now() - datetime.timedelta(1)
modified_since_param = (datetime.datetime.now() - datetime.timedelta(90)).strftime('%Y-%m-%dT00:00:00Z')
basic_auth = 'Basic ' + base64.b64encode(os.environ['ASANA_API_KEY'] + ':')

overdue_comment_text = 'This is a friendly (automated) reminder that this task is past its due date. Please update it so that others have a better sense of when it\'ll be complete. Thanks!'
stale_comment_text = 'This is a friendly (automated) reminder that this task is getting stale. Please update it if it\'s still prioritized. Or kill it, that\'s cool too. Thanks!'
apikey = 'xxx'
apikeyencoded = b64encode(bytes(apikey, "ascii")).decode("ascii")
#apikeyencoded = b64encode(b"0/97cc0274d52812ecc162f851c1f8283c").decode("ascii")
basic_auth = 'Basic ' + str(apikeyencoded)
#print (basic_auth)
#bearer_auth = 'Bearer ' + apikey
#print (bearer_auth)

overdue_comment_text = 'Bitte um ein Update zu dieser Aufgabe. Schreiben Sie ein Kommentar falls es etwas neues gibt oder wenn Hilfe vom Team notwendig ist. ~~~[RU] Напоминание: эта задача просрочена. Прошу прокомментировать. ~~~[ЕN] This task is past its due date. Please write a comment with an update.'

stale_comment_text = 'Aufgabe älter als 30 Tage. Bitte erledigen Sie die Aufgabe oder schreiben ein Kommentar warum die Aufgabe nicht erledigt werden kann. ~~~[RU] Напоминание: эта задача становится устаревшей - сделана более 30 дней назад. Прошу решить задачу или прокомментировать. ~~~[EN] This task is getting old - created over 30 days ago. Please complete it or add a comment.'


def data_for(path):
request = urllib2.Request('https://app.asana.com/api/1.0' + path)
request.add_header('Authorization', basic_auth)
return json.load(urllib2.urlopen(request))['data']

###################
# TESTING Asana API access via python, not using the ASANA-PYTHONG client library
###################

# Simple test that urllib is imported correctly.
#html = urllib.request.urlopen('https://arstechnica.com').read()
#print(html)

# Simple test that urllib HEADERS are setup and authorization works.
#request1 = urllib.request.Request('https://app.asana.com/api/1.0/users/me')
#request1.add_header('Authorization', basic_auth)
#result1 = urllib.request.urlopen(request1)
#response1 = json.load(result1)
#print (response1)



###################
# SCRIPT STARTS
###################

# python functions?
def data_for(path):
request = urllib.request.Request('https://app.asana.com/api/1.0' + path)
print('API requested from :::::: ' + 'https://app.asana.com/api/1.0' + path)

request.add_header('Authorization', basic_auth)
result = urllib.request.urlopen(request)
return json.load(result)['data']

#request = urllib.request.urlopen('https://app.asana.com/api/1.0' + path)
#request.add_header('Authorization', basic_auth)
#return json.load(urllib.urlopen(request))['data']

def comment_on_task(task_id, comment_text):
data = urllib.urlencode({'text': comment_text})
request = urllib2.Request('https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data)
request.add_header('Authorization', basic_auth)
return urllib2.urlopen(request)
data = urllib.parse.urlencode({'text': comment_text})

request = urllib.request.Request('https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data=bytes(data, "ascii"))
request.add_header('Authorization', basic_auth)
request.add_header('Content-Type', 'application/x-www-form-urlencoded')
result = urllib.request.urlopen(request)
# NOT SURE how to print full request URL payload string... learn!
#print ('Full URL for the comment :::::: ' + str(result))
return result

#request = urllib.request.urlopen('https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data)
#request.add_header('Authorization', basic_auth)
#return urllib.urlopen(request)

#get all USERS
users = data_for('/users')

#cycle through USERS
for user in users:
tasks = data_for('/tasks?workspace=' + workspace_id + '&assignee=' + str(user['id']) + '&modified_since=' + modified_since_param)
i = 0
for task in tasks:
print '{}/{} tasks for {}'.format(i, len(tasks), user['name'])
if user['name'] == 'George':

tasks = data_for('/tasks?workspace=' + workspace_id + '&assignee=' + str(user['id']) + '&modified_since=' + modified_since_param)
i = 0

#cycle through TASKS
for task in tasks:
print ('[{}/{} tasks for {}]'.format(i, len(tasks), user['name']))

task_data = data_for('/tasks/' + str(task['id']))
stories = data_for('/tasks/' + str(task['id']) + '/stories')
task_data = data_for('/tasks/' + str(task['id']))
stories = data_for('/tasks/' + str(task['id']) + '/stories')

if 'due_on' in task_data and task_data['due_on'] is not None and task_data['completed'] is not True:
due_date = datetime.datetime.strptime(task_data['due_on'], '%Y-%m-%d')
if due_date < yesterday:
comment_on_task(task['id'], overdue_comment_text)
print 'overdue; commented'
if 'due_on' in task_data and task_data['due_on'] is not None and task_data['completed'] is not True:
due_date = datetime.datetime.strptime(task_data['due_on'], '%Y-%m-%d')
if due_date < yesterday:
print (':::::: OVERDUE caught! ::::::')
comment_on_task(task['id'], overdue_comment_text)
print (':::::: OVERDUE; commented ::::::')
### BREAK LOOP ###
#raise SystemExit('EXIT: Just one success is enough for now...')

if len(stories) > 0 and datetime.datetime.strptime(stories[-1]['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') < thirty_days_ago and task_data['completed'] is not True:
comment_on_task(task['id'], stale_comment_text)
print 'stale; commented'
if len(stories) > 0 and datetime.datetime.strptime(stories[-1]['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') < thirty_days_ago and task_data['completed'] is not True:
print (':::::: STALE caught! ::::::')
comment_on_task(task['id'], stale_comment_text)
print (':::::: STALE; commented ::::::')
### BREAK LOOP ###
#raise SystemExit('EXIT: Just one success is enough for now...')

i += 1
i += 1

print 'done!'
print ('done!')
93 changes: 93 additions & 0 deletions asana_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import base64
from base64 import b64encode
import datetime
import json
import os
# import urllib
import urllib.request as urllib
from urllib.request import urlopen
import urllib.parse



###################
# DEFINE VARIABLES
###################

# ASANA_WORKSPACE_ID
# ASANA_API_KEY

workspace_id = 'xxx'
thirty_days_ago = datetime.datetime.now() - datetime.timedelta(30)
yesterday = datetime.datetime.now() - datetime.timedelta(1)
modified_since_param = (datetime.datetime.now() - datetime.timedelta(90)).strftime('%Y-%m-%dT00:00:00Z')

apikey = 'xxx'
apikeyencoded = b64encode(bytes(apikey, "ascii")).decode("ascii")
#apikeyencoded = b64encode(b"0/97cc0274d52812ecc162f851c1f8283c").decode("ascii")
basic_auth = 'Basic ' + str(apikeyencoded)
#print (basic_auth)
#bearer_auth = 'Bearer ' + apikey
#print (bearer_auth)

overdue_comment_text = 'Automatische Erinnerung: Fälligkeitstermin der Aufgabe überschritten. Bitte um Kommentar. ~~~ Автоматическое напоминание: эта задача просрочена. Прошу прокомментировать. ~~~ Automatic reminder: this task is past its due date. Please comment on this.'

stale_comment_text = 'Automatische Erinnerung: diese Aufgabe wird alt. Bitte um Kommentar, wenn es noch Priorität hat. Oder schliessen Sie die Aufgabe! ~~~ Это дружественное напоминание о том, что эта задача становится устаревшей. Eсли она по-прежнему приоритет, прошу прокомментировать. Или стереть задачу если она не нужна. ~~~ This is a friendly reminder that this task is getting stale. Please update it if its still a priority. Or kill it.'



###################
# TESTING Asana API access via python, not using the ASANA-PYTHONG client library
###################

# Simple test that urllib is imported correctly.
#html = urllib.request.urlopen('https://arstechnica.com').read()
#print(html)

# Simple test that urllib HEADERS are setup and authorization works.
request1 = urllib.request.Request('https://app.asana.com/api/1.0/users/me')
request1.add_header('Authorization', basic_auth)
result1 = urllib.request.urlopen(request1)
response1 = json.load(result1)
print (response1)



###################
# SCRIPT STARTS
###################

# python functions?
def data_for(path):
request = urllib.request.Request('https://app.asana.com/api/1.0' + path)
print('API requested from :::::: ' + 'https://app.asana.com/api/1.0' + path)

request.add_header('Authorization', basic_auth)
result = urllib.request.urlopen(request)
return json.load(result)['data']

#request = urllib.request.urlopen('https://app.asana.com/api/1.0' + path)
#request.add_header('Authorization', basic_auth)
#return json.load(urllib.urlopen(request))['data']

def comment_on_task(task_id, comment_text):
data = urllib.parse.urlencode({'text': comment_text})

request = urllib.request.Request('https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data)
print('API requested from :::::: ' + 'https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data)

request.add_header('Authorization', basic_auth)
result = urllib.request.urlopen(request)
return result

#request = urllib.request.urlopen('https://app.asana.com/api/1.0/tasks/' + str(task_id) + '/stories', data)
#request.add_header('Authorization', basic_auth)
#return urllib.urlopen(request)

#get all USERS
users = data_for('/users')

#cycle through USERS
for user in users:
if user['name'] == 'George':
print ('FOUND GEORGE!')
1 change: 1 addition & 0 deletions runtime.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python-3.7.0