require 'basecamp' require 'google_spreadsheet' require 'yaml' require 'erb' require 'pp' begin require 'activesupport' rescue LoadError abort <<-ERROR The 'activesupport' library could not be loaded. If you have RubyGems installed you can install it with "gem install activesupport". ERROR end module CampfireStick # Pitch a tent and sync your google spreadsheet with Basecamp time tracking. # tent = CampfireStick::Tent.new # tent.pitch # pitching your tent requires config/auth.yml with the email and password # of the admin gmail account to which you share your timesheet. class Tent def pitch auth = IO.read(File.dirname(__FILE__) + "/../config/auth.yml") # should only be one entry manager = YAML::load(ERB.new(auth).result).symbolize_keys.shift # Ex. [:campfirestick, {'email' => 'campfirestick@gmail.com', 'password' => 'campfirestick123'}] gs = GoogleSpreadsheet.new credentials = manager[1].symbolize_keys gs.authenticate(credentials[:email], credentials[:password]) spreadsheets = gs.get_my_spreadsheets users_projects = {} spreadsheets["entry"].each do |spreadsheet| # loop all spreadsheets in manager's docs # timesheet should start with '_time' (see auth.yml) next if spreadsheet["title"][0]["content"].to_s.downcase.grep(/^#{credentials[:spreadsheet_prefix]}/).empty? doc_uri = spreadsheet["link"][0]["href"] doc_data = gs.create_datastructure_from_xml(gs.get_feed(doc_uri).body) listfeed_uri = doc_data["entry"][0]["link"][0]["href"] listfeed_data = gs.create_datastructure_from_xml(gs.get_feed(listfeed_uri).body) user_email = listfeed_data["author"][0]["email"][0] users_projects[user_email] = group_time_entries_by_project(listfeed_data) end sync_basecamp credentials[:basecamp_domain], credentials[:basecamp_username], credentials[:basecamp_password], users_projects puts '**Finished**' end # Returns an array of 2-element arrays with project name in position 0 and arrays of spreadsheet rows in position 1 #Ex. #[["Project A", [{:description=>"begin development", :project=>"Project A", :date=>"1/1/2008", :hours=>"15"}, {:description=>"jkghkk", :project=>"Project A", :date=>"1/2/2008", :hours=>"10"}]], #[["Project B", [{:description=>"begin development", :project=>"Project B", :date=>"1/1/2008", :hours=>"25"}, {:description=>"adfasdfasf", :project=>"Project B", :date=>"1/2/2008", :hours=>"20"}]]] # def group_time_entries_by_project(listfeed) # loop rows time = [] listfeed["entry"].each do |row| time << {:date => row["date"][0].strip, :project => row["project"][0].strip, :description => row["description"][0].strip, :hours => row["hours"][0].strip} end # group_by is a bit hackish here but not bad return time.group_by { |row| row[:project] } end # 1-way sync basecamp project time from spreadsheet data def sync_basecamp(domain, username, password, users_projects) session = Basecamp.new(domain, username, password, true) # use ssl users_projects.each do |useremail, projects| projects.each do |proj_time_rows| # get proj, comp, and user id's proj = session.projects.find {|bcproj| bcproj.name.downcase == proj_time_rows[0].downcase} company = proj.company user = session.people(company.id).find {|person| person["email-address"] == useremail} # get all user's time entries for project bc_time_entries = session.records 'time-entry', "/time/report/#{user.id}/0/0/p#{proj.id}" # delete existing entries by proj bc_time_entries.each do |entry| session.record "/projects/#{proj.id}/time/delete_entry/#{entry['id']}" end # add all from spreadsheet proj_time_rows[1].each do |row| session.record "/time/save_entry", :entry => {:person_id => user.id, :project_id => proj.id, :date => row[:date], :description => row[:description], :hours => row[:hours]} end end end end end end