Skip to content

Instantly share code, notes, and snippets.

@mike-north
Last active July 31, 2022 04:34
Show Gist options
  • Save mike-north/0d0dcbca857752f9e575a344e653d50f to your computer and use it in GitHub Desktop.
Save mike-north/0d0dcbca857752f9e575a344e653d50f to your computer and use it in GitHub Desktop.
Calendar from Asana Tasks
ASANA_KEY_MIKE="/// REPLACE WITH ASANA KEY 1 ///"
ASANA_KEY_LISA="/// REPLACE WITH ASANA KEY 1 ///"
.env
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/spec/examples.txt
/test/tmp/
/test/version_tmp/
/tmp/
# Used by dotenv library to load environment variables.
# .env
# Ignore Byebug command history file.
.byebug_history
## Specific to RubyMotion:
.dat*
.repl_history
build/
*.bridgesupport
build-iPhoneOS/
build-iPhoneSimulator/
## Specific to RubyMotion (use of CocoaPods):
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# vendor/Pods/
## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/
## Environment normalization:
/.bundle/
/vendor/bundle
/lib/bundler/man/
# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*
require './myapp'
run Sinatra::Application
source 'https://rubygems.org'
gem 'rack'
gem 'sinatra'
gem 'asana'
gem 'icalendar'
gem 'dotenv'
gem 'puma'
gem 'activesupport'
GEM
remote: https://rubygems.org/
specs:
activesupport (7.0.3.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
asana (1.0.0)
faraday (~> 1.0)
faraday_middleware (~> 1.0)
faraday_middleware-multi_json (~> 0.0)
oauth2 (>= 1.4, < 3)
concurrent-ruby (1.1.10)
dotenv (2.8.1)
faraday (1.10.0)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
faraday_middleware-multi_json (0.0.6)
faraday_middleware
multi_json
hashie (5.0.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
icalendar (2.8.0)
ice_cube (~> 0.16)
ice_cube (0.16.4)
jwt (2.4.1)
minitest (5.16.2)
multi_json (1.15.0)
multi_xml (0.6.0)
multipart-post (2.2.3)
mustermann (2.0.2)
ruby2_keywords (~> 0.0.1)
nio4r (2.5.8)
oauth2 (2.0.6)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
rash_alt (>= 0.4, < 1)
version_gem (~> 1.1)
puma (5.6.4)
nio4r (~> 2.0)
rack (2.2.4)
rack-protection (2.2.2)
rack
rash_alt (0.4.12)
hashie (>= 3.4)
ruby2_keywords (0.0.5)
sinatra (2.2.2)
mustermann (~> 2.0)
rack (~> 2.2)
rack-protection (= 2.2.2)
tilt (~> 2.0)
tilt (2.0.11)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
version_gem (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
activesupport
asana
dotenv
icalendar
puma
rack
sinatra
BUNDLED WITH
1.17.3
require 'dotenv/load'
require 'sinatra'
require 'asana'
require 'icalendar'
require 'active_support/time'
Dotenv.require_keys("ASANA_KEY_MIKE")
def get_tasks
client = Asana::Client.new do |c|
c.authentication :access_token, ENV['ASANA_KEY_MIKE']
end
workspace = client.workspaces.find_all.first
mike = client.users.me
task_list = client.user_task_lists.get_user_task_list_for_user(user_gid: mike.gid, workspace: workspace.gid)
task_list.tasks(completed_since: nil, options: {fields: ["gid", "name", "due_at", "notes", "projects", "start_at"]})
end
TIMED_TASK_FORMAT = /\[([0-9]+)m\]\s(.*)$/
get '/mike-calendar.ics', :provides => :text do
tasks = get_tasks
cal = Icalendar::Calendar.new
tasks.each do |task|
matches = TIMED_TASK_FORMAT.match(task.name)
if matches != nil then
duration_s, summary = matches.captures
duration_i = duration_s.to_i
if duration_i != nil and task.due_at != nil then
end_at = DateTime.parse(task.due_at)
project = task.projects.last
url = "https://app.asana.com/0/#{project ? project.gid : '0'}/#{task.gid}"
cal.event do |e|
e.dtstart = Icalendar::Values::DateTime.new end_at - duration_i.minutes, 'tzid' => 'Europe/London'
e.dtend = Icalendar::Values::DateTime.new end_at, 'tzid' => 'Europe/London'
e.organizer = %w(mailto:mnorth@stripe.com) # one or more email recipients (required)
e.attendee = %w(mailto:mnorth@stripe.com) # one or more email recipients (required)
e.summary = summary
e.description = "#{task.notes} \n #{url}"
e.ip_class = "PUBLIC"
e.url = "#{url}"
e.alarm do |a|
a.summary = summary
a.description = "15 minute warning"
a.trigger = "-PT15M" # 15m
end
e.alarm do |a|
a.summary = summary
a.description = "5 minute warning"
a.trigger = "-PT5M" # 5m
end
end
end
end
end
cal.to_ical
end
get '/lisa-calendar.ics', :provides => :text do
tasks = get_tasks
cal = Icalendar::Calendar.new
tasks.each do |task|
matches = TIMED_TASK_FORMAT.match(task.name)
if matches != nil then
duration_s, summary = matches.captures
duration_i = duration_s.to_i
if duration_i != nil and task.due_at != nil then
puts task.due_at
end_at = DateTime.parse(task.due_at)
cal.event do |e|
e.dtstart = Icalendar::Values::DateTime.new end_at - duration_i.minutes, 'tzid' => 'Europe/London'
e.dtend = Icalendar::Values::DateTime.new end_at, 'tzid' => 'Europe/London'
e.organizer = %w(mailto:lhuangnorth@microsoft.com) # one or more email recipients (required)
e.attendee = %w(mailto:lhuangnorth@microsoft.com) # one or more email recipients (required)
e.summary = summary
e.description = "#{task.notes}"
e.ip_class = "PUBLIC"
e.url = "https://app.asana.com/0/0/#{task.gid}"
e.alarm do |a|
a.summary = summary
a.description = "15 minute warning"
a.trigger = "-PT15M" # 15m
end
e.alarm do |a|
a.summary = summary
a.description = "5 minute warning"
a.trigger = "-PT5M" # 5m
end
end
end
end
end
cal.to_ical
end
web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment