From 78b68ae4c30240a0e4fe1ab3b3c27fa916fe3701 Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Fri, 30 Jun 2017 17:33:40 -0400 Subject: [PATCH 1/9] Update Google Agents Updates google-api-client to 0.13 along with GoogleCalendarPublishAgent and GoogleTranslationAgent to newer API signatures. In preparation for including a google-cloud-bigquery gem and Agent which would otherwise have dependency version mismatches. May break backwards compatibility for the GoogleCalendarPublishAgent due to Google's new preferred authentication method. PKCS12 keys are no longer support by the gem, in favor of RSA private keys / JSON key files. The new API no longer uses a discovery method and implements methods in Ruby, adopting snake case names for object keys. So `dateTime` becomes `date_time`. `time_zone` also appears to now be required. --- Gemfile | 14 +- Gemfile.lock | 175 +++++---- Procfile | 1 + .../agents/google_calendar_publish_agent.rb | 36 +- app/models/agents/google_translation_agent.rb | 30 +- lib/google_calendar.rb | 58 +-- ...hecks_if_it_can_handle_multiple_events.yml | 359 +++++++----------- .../google_calendar_publish_agent_spec.rb | 23 +- 8 files changed, 326 insertions(+), 370 deletions(-) diff --git a/Gemfile b/Gemfile index 7eb85a4a..725e7241 100644 --- a/Gemfile +++ b/Gemfile @@ -44,11 +44,14 @@ gem 'slack-notifier', '~> 1.0.0' # SlackAgent gem 'hypdf', '~> 1.0.10' # PDFInfoAgent # Weibo Agents -# FIXME needs to loosen omniauth dependency -gem 'weibo_2', github: 'dsander/weibo_2', branch: 'master' +# FIXME needs to loosen omniauth dependency, add rest-client +gem 'weibo_2', github: 'albertsun/weibo_2', branch: 'master' # GoogleCalendarPublishAgent and GoogleTranslateAgent -gem 'google-api-client', '~> 0.7.1', require: 'google/api_client' +gem 'google-api-client', '~> 0.13' +# gem 'google-api-client', '~> 0.7.0' #, require: 'google/api_client' +gem 'google-cloud-translate', '~> 1.0.0', require: 'google/cloud/translate' +# gem 'google-cloud-bigquery', '~> 0.27.0', require: 'google/cloud/bigquery' # Twitter Agents gem 'twitter', github: 'sferik/twitter' # Must to be loaded before cantino-twitter-stream. @@ -56,7 +59,8 @@ gem 'twitter-stream', github: 'cantino/twitter-stream', branch: 'huginn' gem 'omniauth-twitter', '~> 1.3.0' # Tumblr Agents -gem 'tumblr_client', github: 'tumblr/tumblr_client', branch: 'master', ref: '0c59b04e49f2a8c89860613b18cf4e8f978d8dc7' # '>= 0.8.5' +# until merge of https://github.com/tumblr/tumblr_client/pull/61 +gem 'tumblr_client', github: 'albertsun/tumblr_client', branch: 'master', ref: 'e046fe6e39291c173add0a49081630c7b60a36c7' gem 'omniauth-tumblr', '~> 1.2' # Dropbox Agents @@ -147,7 +151,7 @@ group :development do end group :test do - gem 'coveralls', '~> 0.7.4', require: false + gem 'coveralls', '~> 0.8.12', require: false gem 'capybara', '~> 2.13.0' gem 'capybara-select2', require: false gem 'delorean' diff --git a/Gemfile.lock b/Gemfile.lock index 1c87fe59..3329805d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,28 @@ +GIT + remote: https://github.com/albertsun/tumblr_client.git + revision: e046fe6e39291c173add0a49081630c7b60a36c7 + ref: e046fe6e39291c173add0a49081630c7b60a36c7 + branch: master + specs: + tumblr_client (0.8.5) + faraday (<= 1.0.0) + faraday_middleware (<= 1.0.0) + json + mime-types + oauth + simple_oauth + +GIT + remote: https://github.com/albertsun/weibo_2.git + revision: ac38d04434747c4b88e86c5337cd436d00c34349 + branch: master + specs: + weibo_2 (0.1.7) + hashie (~> 3) + multi_json (~> 1) + oauth2 (~> 1) + rest-client (>= 2.0) + GIT remote: https://github.com/amatsuda/kaminari.git revision: abbf93d557208ee1d0b612c612cd079f86ed54f4 @@ -35,17 +60,6 @@ GIT activerecord (>= 3.0, < 5.2) delayed_job (>= 3.0, < 5) -GIT - remote: https://github.com/dsander/weibo_2.git - revision: e5b77f21a7e9a666b582c48e16b1e96fca198cf8 - branch: master - specs: - weibo_2 (0.1.7) - hashie (~> 3) - multi_json (~> 1) - oauth2 (~> 1) - rest-client (~> 1.8) - GIT remote: https://github.com/lostisland/faraday_middleware.git revision: 59088da02940d0ee2010b2e3156343346767c31e @@ -70,20 +84,6 @@ GIT naught (~> 1.0) simple_oauth (~> 0.3.0) -GIT - remote: https://github.com/tumblr/tumblr_client.git - revision: 0c59b04e49f2a8c89860613b18cf4e8f978d8dc7 - ref: 0c59b04e49f2a8c89860613b18cf4e8f978d8dc7 - branch: master - specs: - tumblr_client (0.8.5) - faraday (~> 0.9.0) - faraday_middleware (~> 0.9) - json - mime-types - oauth - simple_oauth - PATH remote: vendor/gems/dotenv-2.0.1 specs: @@ -135,10 +135,6 @@ GEM addressable (2.5.1) public_suffix (~> 2.0, >= 2.0.2) arel (8.0.0) - autoparse (0.3.3) - addressable (>= 2.3.1) - extlib (>= 0.9.15) - multi_json (>= 1.0.0) aws-sdk-core (2.2.15) jmespath (~> 1.0) bcrypt (3.1.11) @@ -186,16 +182,18 @@ GEM colorize (0.7.7) concurrent-ruby (1.0.5) cookiejar (0.3.2) - coveralls (0.7.12) - multi_json (~> 1.10) - rest-client (>= 1.6.8, < 2) - simplecov (~> 0.9.1) + coveralls (0.8.21) + json (>= 1.8, < 3) + simplecov (~> 0.14.1) term-ansicolor (~> 1.3) - thor (~> 0.19.1) + thor (~> 0.19.4) + tins (~> 1.6) crack (0.4.3) safe_yaml (~> 1.0.0) daemons (1.1.9) debug_inspector (0.0.2) + declarative (0.0.9) + declarative-option (0.1.0) delorean (2.1.0) chronic devise (4.3.0) @@ -206,7 +204,7 @@ GEM warden (~> 1.2.3) diff-lcs (1.3) docile (1.1.5) - domain_name (0.5.24) + domain_name (0.5.20170404) unf (>= 0.0.5, < 1.0.0) dropbox-api (0.4.2) hashie @@ -236,8 +234,7 @@ GEM evernote-thrift oauth (>= 0.4.1) execjs (2.6.0) - extlib (0.9.16) - faraday (0.9.2) + faraday (0.12.1) multipart-post (>= 1.2, < 3) feedjira (2.1.0) faraday (>= 0.9) @@ -262,17 +259,29 @@ GEM rails (>= 3.0) globalid (0.4.0) activesupport (>= 4.2.0) - google-api-client (0.7.1) - addressable (>= 2.3.2) - autoparse (>= 0.3.3) - extlib (>= 0.9.15) - faraday (>= 0.9.0) - jwt (>= 0.1.5) - launchy (>= 2.1.1) - multi_json (>= 1.0.0) - retriable (>= 1.4) - signet (>= 0.5.0) - uuidtools (>= 2.1.0) + google-api-client (0.13.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (~> 0.5) + httpclient (>= 2.8.1, < 3.0) + mime-types (~> 3.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.0) + google-cloud-core (1.0.0) + google-cloud-env (~> 1.0) + googleauth (~> 0.5.1) + google-cloud-env (1.0.0) + faraday (~> 0.11) + google-cloud-translate (1.0.0) + google-cloud-core (~> 1.0) + googleauth (~> 0.5.1) + googleauth (0.5.1) + faraday (~> 0.9) + jwt (~> 1.4) + logging (~> 2.0) + memoist (~> 0.12) + multi_json (~> 1.11) + os (~> 0.9) + signet (~> 0.7) guard (2.13.0) formatador (>= 0.2.4) listen (>= 2.7, <= 4.0) @@ -293,7 +302,7 @@ GEM guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) hashdiff (0.3.2) - hashie (3.4.6) + hashie (3.5.5) haversine (0.3.0) hipchat (1.2.0) httparty @@ -306,12 +315,13 @@ GEM http-cookie (~> 1.0) http-form_data (~> 1.0.1) http_parser.rb (~> 0.6.0) - http-cookie (1.0.2) + http-cookie (1.0.3) domain_name (~> 0.5) http-form_data (1.0.1) http_parser.rb (0.6.0) httparty (0.14.0) multi_xml (>= 0.5.2) + httpclient (2.8.3) huginn_agent (0.4.0) thor hypdf (1.0.10) @@ -326,7 +336,7 @@ GEM json (1.8.6) jsonpath (0.8.3) multi_json - jwt (1.4.1) + jwt (1.5.6) kgio (2.10.0) kramdown (1.3.3) launchy (2.4.2) @@ -342,6 +352,10 @@ GEM listen (3.0.5) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) + little-plugger (1.1.4) + logging (2.2.2) + little-plugger (~> 1.1) + multi_json (~> 1.10) loofah (2.0.3) nokogiri (>= 1.5.9) lumberjack (1.0.10) @@ -349,17 +363,20 @@ GEM systemu (~> 2.6.2) mail (2.6.5) mime-types (>= 1.16, < 4) + memoist (0.16.0) memoizable (0.4.2) thread_safe (~> 0.3, >= 0.3.1) method_source (0.8.2) - mime-types (2.99.3) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) mimemagic (0.3.1) mini_magick (4.2.3) mini_portile2 (2.1.0) minitest (5.10.2) mqtt (0.3.1) multi_json (1.12.1) - multi_xml (0.5.5) + multi_xml (0.6.0) multipart-post (2.0.0) mysql2 (0.3.20) naught (1.1.0) @@ -368,7 +385,7 @@ GEM net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (3.0.2) - netrc (0.10.3) + netrc (0.11.0) nio4r (2.0.0) nokogiri (1.7.2) mini_portile2 (~> 2.1.0) @@ -376,8 +393,8 @@ GEM nenv (~> 0.1) shellany (~> 0.0) oauth (0.4.7) - oauth2 (1.2.0) - faraday (>= 0.8, < 0.10) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) @@ -410,6 +427,7 @@ GEM omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) orm_adapter (0.5.0) + os (0.9.6) pg (0.18.3) poltergeist (1.8.1) capybara (~> 2.1) @@ -427,7 +445,7 @@ GEM pry-rails (0.3.4) pry (>= 0.9.10) public_suffix (2.0.5) - rack (2.0.2) + rack (2.0.3) rack-livereload (0.3.16) rack rack-test (0.6.3) @@ -467,14 +485,18 @@ GEM rb-kqueue (0.2.4) ffi (>= 0.5.0) ref (2.0.0) + representable (3.0.4) + declarative (< 0.1.0) + declarative-option (< 0.2.0) + uber (< 0.2.0) responders (2.4.0) actionpack (>= 4.2.0, < 5.3) railties (>= 4.2.0, < 5.3) - rest-client (1.8.0) + rest-client (2.0.2) http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - retriable (2.0.2) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) + retriable (3.0.2) rr (1.1.2) rspec (3.5.0) rspec-core (~> 3.5.0) @@ -524,17 +546,17 @@ GEM shellany (0.0.1) shoulda-matchers (3.0.0) activesupport (>= 4.0.0) - signet (0.5.1) - addressable (>= 2.2.3) - faraday (>= 0.9.0.rc5) - jwt (>= 0.1.5) - multi_json (>= 1.0.0) + signet (0.7.3) + addressable (~> 2.3) + faraday (~> 0.9) + jwt (~> 1.5) + multi_json (~> 1.10) simple_oauth (0.3.1) - simplecov (0.9.2) + simplecov (0.14.1) docile (~> 1.1.0) - multi_json (~> 1.0) - simplecov-html (~> 0.9.0) - simplecov-html (0.9.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.1) slack-notifier (1.0.0) slop (3.6.0) spectrum-rails (1.3.4) @@ -557,7 +579,7 @@ GEM net-scp (>= 1.1.2) net-ssh (>= 2.8.0) systemu (2.6.4) - term-ansicolor (1.3.2) + term-ansicolor (1.6.0) tins (~> 1.0) therubyracer (0.12.3) libv8 (~> 3.16.14.15) @@ -565,7 +587,7 @@ GEM thor (0.19.4) thread_safe (0.3.6) tilt (2.0.7) - tins (1.10.1) + tins (1.15.0) treetop (1.5.3) polyglot (~> 0.3) twilio-ruby (3.11.6) @@ -576,18 +598,18 @@ GEM ethon (>= 0.7.1) tzinfo (1.2.3) thread_safe (~> 0.1) + uber (0.1.0) uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.3) + unf_ext (0.0.7.4) unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) uuid (2.3.7) macaddr (~> 1.0) - uuidtools (2.1.5) vcr (3.0.3) warden (1.2.7) rack (>= 1.0) @@ -627,7 +649,7 @@ DEPENDENCIES capybara (~> 2.13.0) capybara-select2 coffee-rails (~> 4.2) - coveralls (~> 0.7.4) + coveralls (~> 0.8.12) daemons (~> 1.1.9) delayed_job! delayed_job_active_record! @@ -647,7 +669,8 @@ DEPENDENCIES foreman (~> 0.63.0) geokit (~> 1.8.4) geokit-rails (~> 2.2.0) - google-api-client (~> 0.7.1) + google-api-client (~> 0.13) + google-cloud-translate (~> 1.0.0) guard (~> 2.13.0) guard-livereload (~> 2.5.1) guard-rspec (~> 4.6.4) diff --git a/Procfile b/Procfile index 1013ab34..b3e737c0 100644 --- a/Procfile +++ b/Procfile @@ -5,6 +5,7 @@ # Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job) web: bundle exec rails server -p ${PORT-3000} -b ${IP-0.0.0.0} jobs: bundle exec rails runner bin/threaded.rb +dj: bundle exec script/delayed_job run # Old version with separate processes (use this if you have issues with the threaded version) # web: bundle exec rails server diff --git a/app/models/agents/google_calendar_publish_agent.rb b/app/models/agents/google_calendar_publish_agent.rb index c852d48c..b2f5ce04 100644 --- a/app/models/agents/google_calendar_publish_agent.rb +++ b/app/models/agents/google_calendar_publish_agent.rb @@ -1,11 +1,12 @@ require 'json' +require 'google/apis/calendar_v3' module Agents class GoogleCalendarPublishAgent < Agent cannot_be_scheduled! no_bulk_receive! - gem_dependency_check { defined?(Google) && defined?(Google::APIClient) } + gem_dependency_check { defined?(Google) && defined?(Google::Apis::CalendarV3) } description <<-MD The Google Calendar Publish Agent creates events on your Google Calendar. @@ -23,6 +24,21 @@ module Agents 5. Persist the generated private key to a path, ie: `/home/huginn/a822ccdefac89fac6330f95039c492dfa3ce6843.p12` 6. Grant access via google calendar UI to the service account email address for each calendar you wish to manage. For a whole google apps domain, you can [delegate authority](https://developers.google.com/+/domains/authentication/delegation) + An earlier version of Huginn used PKCS12 key files to authenticate. This will no longer work, you should generate a new JSON format keyfile, that will look something like: +
{
+        "type": "service_account",
+        "project_id": "huginn-123123",
+        "private_key_id": "6d6b476fc6ccdb31e0f171991e5528bb396ffbe4",
+        "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
+        "client_email": "huginn-calendar@huginn-123123.iam.gserviceaccount.com",
+        "client_id": "123123...123123",
+        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+        "token_uri": "https://accounts.google.com/o/oauth2/token",
+        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/huginn-calendar%40huginn-123123.iam.gserviceaccount.com"
+      }
+ + Agent Configuration: @@ -32,10 +48,7 @@ module Agents `google` `service_account_email` - The authorised service account. - `google` `key_file` OR `google` `key` - The path to the key file or the key itself. [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) formatting is supported if you want to use a Credential. (E.g., `{% credential google_key %}`) - - `google` `key_secret` - The secret for the key, typically 'notasecret' - + `google` `key_file` OR `google` `key` - The path to the JSON key file above, or the key itself (the value of `private_key`). [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) formatting is supported if you want to use a Credential. (E.g., `{% credential google_key %}`) Set `expected_update_period_in_days` to the maximum amount of time that you'd expect to pass between Events being created by this Agent. @@ -50,10 +63,12 @@ module Agents "summary": "Awesome event", "description": "An example event with text. Pro tip: DateTimes are in RFC3339", "start": { - "dateTime": "2014-10-02T10:00:00-05:00" + "date_time": "2017-06-30T17:00:00-05:00", + "time_zone": "America/New_York" }, "end": { - "dateTime": "2014-10-02T11:00:00-05:00" + "date_time": "2017-06-30T18:00:00-05:00", + "time_zone": "America/New_York" } } } @@ -84,7 +99,7 @@ module Agents 'calendar_id' => 'you@email.com', 'google' => { 'key_file' => '/path/to/private.key', - 'key_secret' => 'notasecret', + 'key' => '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n', 'service_account_email' => '' } } @@ -95,7 +110,10 @@ module Agents incoming_events.each do |event| calendar = GoogleCalendar.new(interpolate_options(options, event), Rails.logger) - calendar_event = JSON.parse(calendar.publish_as(interpolated(event)['calendar_id'], event.payload["message"]).response.body) + calendar_event = calendar.publish_as( + interpolated(event)['calendar_id'], + event.payload["message"] + ) create_event :payload => { 'success' => true, diff --git a/app/models/agents/google_translation_agent.rb b/app/models/agents/google_translation_agent.rb index c54ebe9c..bc14a398 100644 --- a/app/models/agents/google_translation_agent.rb +++ b/app/models/agents/google_translation_agent.rb @@ -2,7 +2,7 @@ module Agents class GoogleTranslationAgent < Agent cannot_be_scheduled! - gem_dependency_check { defined?(Google) && defined?(Google::APIClient) } + gem_dependency_check { defined?(Google) && defined?(Google::Cloud::Translate) } description <<-MD The Translation Agent will attempt to translate text between natural languages. @@ -12,6 +12,8 @@ module Agents Services are provided using Google Translate. You can [sign up](https://cloud.google.com/translate/) to get `google_api_key` which is required to use this agent. The service is **not free**. + To use credentials for the `google_api_key` use the liquid `credential` tag like so `{% credential google-api-key %}` + `to` must be filled with a [translator language code](https://cloud.google.com/translate/docs/languages). `from` is the language translated from. If it's not specified, the API will attempt to detect the source language automatically and return it within the response. @@ -56,7 +58,7 @@ module Agents opts = interpolated(event) opts['content'].each_pair do |key, value| result = translate(value) - translated_event[key] = result.data.translations.last.translated_text + translated_event[key] = result.text end create_event payload: translated_event end @@ -77,16 +79,22 @@ module Agents @translate_service ||= google_client.discovered_api('translate','v2') end + def cloud_translate_service + # https://github.com/GoogleCloudPlatform/google-cloud-ruby/blob/master/google-cloud-translate/lib/google-cloud-translate.rb#L130 + @google_client ||= Google::Cloud::Translate.new(key: interpolated['google_api_key']) + end + def translate(value) - google_client.execute( - api_method: translate_service.translations.list, - parameters: { - format: 'text', - source: translate_from, - target: options["to"], - q: value - } - ) + # google_client.execute( + # api_method: translate_service.translations.list, + # parameters: { + # format: 'text', + # source: translate_from, + # target: options["to"], + # q: value + # } + # ) + cloud_translate_service.translate(value, to: interpolated["to"], from: translate_from, format: "text") end end end diff --git a/lib/google_calendar.rb b/lib/google_calendar.rb index 81a5f2e0..25ab524e 100644 --- a/lib/google_calendar.rb +++ b/lib/google_calendar.rb @@ -1,33 +1,37 @@ +require 'googleauth' +require 'google/apis/calendar_v3' + class GoogleCalendar def initialize(config, logger) @config = config if @config['google']['key'].present? - @key = OpenSSL::PKCS12.new(@config['google']['key'], @config['google']['key_secret']).key + # https://github.com/google/google-auth-library-ruby/issues/65 + # https://github.com/google/google-api-ruby-client/issues/370 + ENV['GOOGLE_PRIVATE_KEY'] = @config['google']['key'] + ENV['GOOGLE_CLIENT_EMAIL'] = @config['google']['service_account_email'] + ENV['GOOGLE_ACCOUNT_TYPE'] = 'service_account' else - @key = Google::APIClient::PKCS12.load_key(@config['google']['key_file'], @config['google']['key_secret']) + ENV['GOOGLE_APPLICATION_CREDENTIALS'] = @config['google']['key_file'] end - @client = Google::APIClient.new(application_name: "Huginn", application_version: "0.0.1") - @client.retries = 2 @logger ||= logger - @calendar = @client.discovered_api('calendar','v3') + # https://github.com/google/google-api-ruby-client/blob/master/MIGRATING.md + @calendar = Google::Apis::CalendarV3::CalendarService.new + + # https://developers.google.com/api-client-library/ruby/auth/service-accounts + # https://developers.google.com/identity/protocols/application-default-credentials + scopes = [Google::Apis::CalendarV3::AUTH_CALENDAR] + @authorization = Google::Auth.get_application_default(scopes) @logger.info("Setup") @logger.debug @calendar.inspect end def auth_as - @client.authorization = Signet::OAuth2::Client.new({ - token_credential_uri: 'https://accounts.google.com/o/oauth2/token', - audience: 'https://accounts.google.com/o/oauth2/token', - scope: 'https://www.googleapis.com/auth/calendar', - issuer: @config['google']['service_account_email'], - signing_key: @key - }); - - @client.authorization.fetch_access_token! + @authorization.fetch_access_token! + @calendar.authorization = @authorization end # who - String: email of user to add event @@ -38,14 +42,15 @@ class GoogleCalendar @logger.info("Attempting to create event for " + who) @logger.debug details.to_yaml - ret = @client.execute( - api_method: @calendar.events.insert, - parameters: {'calendarId' => who, 'sendNotifications' => true}, - body: details.to_json, - headers: {'Content-Type' => 'application/json'} - ) + event = Google::Apis::CalendarV3::Event.new(details.deep_symbolize_keys) + ret = @calendar.insert_event( + who, + event, + send_notifications: true + ) + @logger.debug ret.to_yaml - ret + ret.to_h end def events_as(who, date) @@ -56,14 +61,11 @@ class GoogleCalendar @logger.info("Attempting to receive events for "+who) @logger.debug details.to_yaml - ret = @client.execute( - api_method: @calendar.events.list, - parameters: {'calendarId' => who, 'sendNotifications' => true}, - body: details.to_json, - headers: {'Content-Type' => 'application/json'} - ) + ret = @calendar.list_events( + who + ) @logger.debug ret.to_yaml - ret + ret.to_h end end diff --git a/spec/cassettes/Agents_GoogleTranslationAgent/_receive/checks_if_it_can_handle_multiple_events.yml b/spec/cassettes/Agents_GoogleTranslationAgent/_receive/checks_if_it_can_handle_multiple_events.yml index df6e68e5..f86fa036 100644 --- a/spec/cassettes/Agents_GoogleTranslationAgent/_receive/checks_if_it_can_handle_multiple_events.yml +++ b/spec/cassettes/Agents_GoogleTranslationAgent/_receive/checks_if_it_can_handle_multiple_events.yml @@ -1,20 +1,22 @@ --- http_interactions: - request: - method: get - uri: https://www.googleapis.com/discovery/v1/apis/translate/v2/rest?key=some_api_key + method: post + uri: https://translation.googleapis.com/language/translate/v2?key=some_api_key body: encoding: UTF-8 - string: '' + string: '{"q":["hey what are you doing"],"target":"sv","source":"en","format":"text"}' headers: User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Mac OS X/10.11.6 - (gzip) - Accept-Encoding: - - gzip + - gcloud-ruby/1.0.0 + Google-Cloud-Resource-Prefix: + - projects/ Content-Type: - - '' + - application/json + X-Goog-Api-Client: + - gl-ruby/2.3.4 gccl/1.0.0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: - "*/*" response: @@ -22,154 +24,53 @@ http_interactions: code: 200 message: OK headers: - Expires: - - Tue, 25 Apr 2017 10:49:56 GMT - Date: - - Tue, 25 Apr 2017 10:44:56 GMT - Etag: - - '"YWOzh2SDasdU84ArJnpYek-OMdg/6s__cFeA5l1i01rONlu3TmUQEHs"' - Vary: - - Origin - - X-Origin Content-Type: - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '1870' - Server: - - GSE - Cache-Control: - - public, max-age=300, must-revalidate, no-transform - Age: - - '0' - Alt-Svc: - - quic=":443"; ma=2592000; v="37,36,35" - body: - encoding: ASCII-8BIT - string: !binary |- - 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 - ftEe3bRzPG9nVZiwDp4O/gfEQdY3CBwAAA== - http_version: - recorded_at: Tue, 25 Apr 2017 10:44:56 GMT -- request: - method: get - uri: https://www.googleapis.com/language/translate/v2?format=text&key=some_api_key&q=hey%20what%20are%20you%20doing&source=en&target=sv - body: - encoding: UTF-8 - string: '' - headers: - User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Mac OS X/10.11.6 - (gzip) - Accept-Encoding: - - gzip - Content-Type: - - '' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Expires: - - Tue, 25 Apr 2017 10:44:56 GMT - Date: - - Tue, 25 Apr 2017 10:44:56 GMT - Cache-Control: - - private, max-age=0, must-revalidate, no-transform - Etag: - - '"0Etagq2wejMpn1NuD3Ltqh3qHnw/XGWNxMh7tDHIjrW_w-Ffgk19QCg"' Vary: - Origin + - Referer - X-Origin - Content-Type: - - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN + Date: + - Fri, 30 Jun 2017 14:54:18 GMT + Server: + - ESF + Cache-Control: + - private X-Xss-Protection: - 1; mode=block - Server: - - GSE + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff Alt-Svc: - - quic=":443"; ma=2592000; v="37,36,35" + - quic=":443"; ma=2592000; v="39,38,37,36,35" Transfer-Encoding: - chunked body: encoding: ASCII-8BIT string: !binary |- - H4sIAAAAAAAAAKvmUlBKSSxJVLJSqOZSUFAqKUrMK85JLMnMzysGikUDxcAS - SFKpKSGpFSVASSWP1CyFssQUhfTD24oUUkqVQOpqgUQsF5Cq5QIA9kBPzVwA - AAA= - http_version: - recorded_at: Tue, 25 Apr 2017 10:44:56 GMT + ewogICJkYXRhIjogewogICAgInRyYW5zbGF0aW9ucyI6IFsKICAgICAgewog + ICAgICAgICJ0cmFuc2xhdGVkVGV4dCI6ICJIZWogdmFkIGfDtnIgZHUiCiAg + ICAgIH0KICAgIF0KICB9Cn0K + http_version: + recorded_at: Fri, 30 Jun 2017 14:54:18 GMT - request: - method: get - uri: https://www.googleapis.com/language/translate/v2?format=text&key=some_api_key&q=do%20tell%20more&source=en&target=sv + method: post + uri: https://translation.googleapis.com/language/translate/v2?key=some_api_key body: encoding: UTF-8 - string: '' + string: '{"q":["do tell more"],"target":"sv","source":"en","format":"text"}' headers: User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Mac OS X/10.11.6 - (gzip) - Accept-Encoding: - - gzip + - gcloud-ruby/1.0.0 + Google-Cloud-Resource-Prefix: + - projects/ Content-Type: - - '' + - application/json + X-Goog-Api-Client: + - gl-ruby/2.3.4 gccl/1.0.0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: - "*/*" response: @@ -177,55 +78,53 @@ http_interactions: code: 200 message: OK headers: - Expires: - - Tue, 25 Apr 2017 10:44:56 GMT - Date: - - Tue, 25 Apr 2017 10:44:56 GMT - Cache-Control: - - private, max-age=0, must-revalidate, no-transform - Etag: - - '"0Etagq2wejMpn1NuD3Ltqh3qHnw/ojPXc7YpC7RgGxSvk9qvHc7p0bM"' - Vary: - - Origin - - X-Origin Content-Type: - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN + Vary: + - Origin + - Referer + - X-Origin + Date: + - Fri, 30 Jun 2017 14:54:19 GMT + Server: + - ESF + Cache-Control: + - private X-Xss-Protection: - 1; mode=block - Server: - - GSE + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff Alt-Svc: - - quic=":443"; ma=2592000; v="37,36,35" + - quic=":443"; ma=2592000; v="39,38,37,36,35" Transfer-Encoding: - chunked body: encoding: ASCII-8BIT string: !binary |- - H4sIAAAAAAAAAKvmUlBKSSxJVLJSqOZSUFAqKUrMK85JLMnMzysGikUDxcAS - SFKpKSGpFSVASaWk1KLDS0pKEhVyU4uUQIpqgUQsF5Cq5QIAoYw0jVkAAAA= - http_version: - recorded_at: Tue, 25 Apr 2017 10:44:56 GMT + ewogICJkYXRhIjogewogICAgInRyYW5zbGF0aW9ucyI6IFsKICAgICAgewog + ICAgICAgICJ0cmFuc2xhdGVkVGV4dCI6ICJCZXLDpHR0YSBtZXIiCiAgICAg + IH0KICAgIF0KICB9Cn0K + http_version: + recorded_at: Fri, 30 Jun 2017 14:54:19 GMT - request: - method: get - uri: https://www.googleapis.com/language/translate/v2?format=text&key=some_api_key&q=value2&source=en&target=sv + method: post + uri: https://translation.googleapis.com/language/translate/v2?key=some_api_key body: encoding: UTF-8 - string: '' + string: '{"q":["value2"],"target":"sv","source":"en","format":"text"}' headers: User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Mac OS X/10.11.6 - (gzip) - Accept-Encoding: - - gzip + - gcloud-ruby/1.0.0 + Google-Cloud-Resource-Prefix: + - projects/ Content-Type: - - '' + - application/json + X-Goog-Api-Client: + - gl-ruby/2.3.4 gccl/1.0.0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: - "*/*" response: @@ -233,55 +132,53 @@ http_interactions: code: 200 message: OK headers: - Expires: - - Tue, 25 Apr 2017 10:44:56 GMT - Date: - - Tue, 25 Apr 2017 10:44:56 GMT - Cache-Control: - - private, max-age=0, must-revalidate, no-transform - Etag: - - '"0Etagq2wejMpn1NuD3Ltqh3qHnw/2iNW9phusbWGkf6jtxwOLwZpsUA"' - Vary: - - Origin - - X-Origin Content-Type: - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN + Vary: + - Origin + - Referer + - X-Origin + Date: + - Fri, 30 Jun 2017 14:54:19 GMT + Server: + - ESF + Cache-Control: + - private X-Xss-Protection: - 1; mode=block - Server: - - GSE + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff Alt-Svc: - - quic=":443"; ma=2592000; v="37,36,35" + - quic=":443"; ma=2592000; v="39,38,37,36,35" Transfer-Encoding: - chunked body: encoding: ASCII-8BIT string: !binary |- - H4sIAAAAAAAAAKvmUlBKSSxJVLJSqOZSUFAqKUrMK85JLMnMzysGikUDxcAS - SFKpKSGpFSVASaWyw0uKUlKNlEDytUAilgtI1XIBACGegeVUAAAA - http_version: - recorded_at: Tue, 25 Apr 2017 10:44:56 GMT + ewogICJkYXRhIjogewogICAgInRyYW5zbGF0aW9ucyI6IFsKICAgICAgewog + ICAgICAgICJ0cmFuc2xhdGVkVGV4dCI6ICJ2w6RyZGUyIgogICAgICB9CiAg + ICBdCiAgfQp9Cg== + http_version: + recorded_at: Fri, 30 Jun 2017 14:54:19 GMT - request: - method: get - uri: https://www.googleapis.com/language/translate/v2?format=text&key=some_api_key&q=value1&source=en&target=sv + method: post + uri: https://translation.googleapis.com/language/translate/v2?key=some_api_key body: encoding: UTF-8 - string: '' + string: '{"q":["value1"],"target":"sv","source":"en","format":"text"}' headers: User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Mac OS X/10.11.6 - (gzip) - Accept-Encoding: - - gzip + - gcloud-ruby/1.0.0 + Google-Cloud-Resource-Prefix: + - projects/ Content-Type: - - '' + - application/json + X-Goog-Api-Client: + - gl-ruby/2.3.4 gccl/1.0.0 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: - "*/*" response: @@ -289,38 +186,40 @@ http_interactions: code: 200 message: OK headers: - Expires: - - Tue, 25 Apr 2017 10:44:56 GMT - Date: - - Tue, 25 Apr 2017 10:44:56 GMT - Cache-Control: - - private, max-age=0, must-revalidate, no-transform - Etag: - - '"0Etagq2wejMpn1NuD3Ltqh3qHnw/nFM5Az6_LFcl8SfedeFzG_gVr5Y"' - Vary: - - Origin - - X-Origin Content-Type: - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN + Vary: + - Origin + - Referer + - X-Origin + Date: + - Fri, 30 Jun 2017 14:54:19 GMT + Server: + - ESF + Cache-Control: + - private X-Xss-Protection: - 1; mode=block - Server: - - GSE + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff Alt-Svc: - - quic=":443"; ma=2592000; v="37,36,35" + - quic=":443"; ma=2592000; v="39,38,37,36,35" Transfer-Encoding: - chunked body: encoding: ASCII-8BIT - string: !binary |- - H4sIAAAAAAAAAKvmUlBKSSxJVLJSqOZSUFAqKUrMK85JLMnMzysGikUDxcAS - SFKpKSGpFSVASaWyxJzSVEMlkHQtkIjlAlK1XAC9QY+aUwAAAA== - http_version: - recorded_at: Tue, 25 Apr 2017 10:44:56 GMT -recorded_with: VCR 2.9.2 + string: | + { + "data": { + "translations": [ + { + "translatedText": "value1" + } + ] + } + } + http_version: + recorded_at: Fri, 30 Jun 2017 14:54:19 GMT +recorded_with: VCR 3.0.3 diff --git a/spec/models/agents/google_calendar_publish_agent_spec.rb b/spec/models/agents/google_calendar_publish_agent_spec.rb index 7ca4f02c..a6771174 100644 --- a/spec/models/agents/google_calendar_publish_agent_spec.rb +++ b/spec/models/agents/google_calendar_publish_agent_spec.rb @@ -43,12 +43,13 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do } } end - let(:response_body) do + + let(:response_hash) do {"kind"=>"calendar#event", "etag"=>"\"2908684044040000\"", "id"=>"baz", "status"=>"confirmed", - "htmlLink"=> + "html_link"=> "https://calendar.google.com/calendar/event?eid=foobar", "created"=>"2016-02-01T15:53:41.000Z", "updated"=>"2016-02-01T15:53:42.020Z", @@ -60,20 +61,20 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do "blah-foobar@developer.gserviceaccount.com"}, "organizer"=> {"email"=>calendar_id, - "displayName"=>"Huginn Location Log", + "display_name"=>"Huginn Location Log", "self"=>true}, - "start"=>{"dateTime"=>"2014-10-03T00:30:00+09:30"}, - "end"=>{"dateTime"=>"2014-10-03T01:30:00+09:30"}, - "iCalUID"=>"blah@google.com", + "start"=>{"date_time"=>"2014-10-03T00:30:00+09:30"}, + "end"=>{"date_time"=>"2014-10-03T01:30:00+09:30"}, + "i_cal_uid"=>"blah@google.com", "sequence"=>0, - "reminders"=>{"useDefault"=>true} - }.to_json + "reminders"=>{"use_default"=>true} + } end def setup_mock! fake_interface = Object.new mock(GoogleCalendar).new(agent.interpolate_options(agent.options), Rails.logger) { fake_interface } - mock(fake_interface).publish_as(calendar_id, message) { stub!.response.stub!.body { response_body } } + mock(fake_interface).publish_as(calendar_id, message) { response_hash } end describe 'when the calendar_id is in the options' do @@ -84,7 +85,7 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do agent.receive([event]) }.to change { agent.events.count }.by(1) - expect(agent.events.last.payload).to eq({ "success" => true, "published_calendar_event" => JSON.parse(response_body), "agent_id" => event.agent_id, "event_id" => event.id }) + expect(agent.events.last.payload).to eq({ "success" => true, "published_calendar_event" => response_hash, "agent_id" => event.agent_id, "event_id" => event.id }) end end @@ -101,7 +102,7 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do agent.receive([event]) expect(agent.events.count).to eq(1) - expect(agent.events.last.payload).to eq({ "success" => true, "published_calendar_event" => JSON.parse(response_body), "agent_id" => event.agent_id, "event_id" => event.id }) + expect(agent.events.last.payload).to eq({ "success" => true, "published_calendar_event" => response_hash, "agent_id" => event.agent_id, "event_id" => event.id }) end it 'should allow Liquid in the key' do From f9695499ae9b52e6532352b99017bd3195f5ec5e Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Wed, 5 Jul 2017 10:59:54 -0400 Subject: [PATCH 2/9] add an upgrade warning for google cal publish agent. other cleanup. --- Gemfile | 2 -- Procfile | 1 - app/controllers/application_controller.rb | 7 +++++++ .../agents/google_calendar_publish_agent.rb | 8 ++++++-- .../application/_upgrade_warning.html.erb | 19 +++++++++++++++++++ lib/google_calendar.rb | 9 ++++++++- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index 725e7241..27cf0f85 100644 --- a/Gemfile +++ b/Gemfile @@ -49,9 +49,7 @@ gem 'weibo_2', github: 'albertsun/weibo_2', branch: 'master' # GoogleCalendarPublishAgent and GoogleTranslateAgent gem 'google-api-client', '~> 0.13' -# gem 'google-api-client', '~> 0.7.0' #, require: 'google/api_client' gem 'google-cloud-translate', '~> 1.0.0', require: 'google/cloud/translate' -# gem 'google-cloud-bigquery', '~> 0.27.0', require: 'google/cloud/bigquery' # Twitter Agents gem 'twitter', github: 'sferik/twitter' # Must to be loaded before cantino-twitter-stream. diff --git a/Procfile b/Procfile index b3e737c0..1013ab34 100644 --- a/Procfile +++ b/Procfile @@ -5,7 +5,6 @@ # Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job) web: bundle exec rails server -p ${PORT-3000} -b ${IP-0.0.0.0} jobs: bundle exec rails runner bin/threaded.rb -dj: bundle exec script/delayed_job run # Old version with separate processes (use this if you have issues with the threaded version) # web: bundle exec rails server diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e1b91187..b2354474 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -33,6 +33,7 @@ class ApplicationController < ActionController::Base twitter_oauth_check basecamp_auth_check outdated_docker_image_namespace_check + outdated_google_auth_check end def filtered_agent_return_link(options = {}) @@ -70,6 +71,12 @@ class ApplicationController < ActionController::Base @outdated_docker_image_namespace = ENV['OUTDATED_DOCKER_IMAGE_NAMESPACE'] == 'true' end + def outdated_google_auth_check + @outdated_google_cal_agents = current_user.agents.where("type like 'Agents::GoogleCalendarPublishAgent'").select do |agent| + agent.options['google']['key_secret'].present? + end + end + def agent_params return {} unless params[:agent] @agent_params ||= begin diff --git a/app/models/agents/google_calendar_publish_agent.rb b/app/models/agents/google_calendar_publish_agent.rb index b2f5ce04..b2b13875 100644 --- a/app/models/agents/google_calendar_publish_agent.rb +++ b/app/models/agents/google_calendar_publish_agent.rb @@ -21,7 +21,7 @@ module Agents 2. New project -> Huginn 3. APIs & Auth -> Enable google calendar 4. Credentials -> Create new Client ID -> Service Account - 5. Persist the generated private key to a path, ie: `/home/huginn/a822ccdefac89fac6330f95039c492dfa3ce6843.p12` + 5. Download the JSON keyfile and save it to a path, ie: `/home/huginn/Huginn-5d12345678cd.json`. Or open that file and copy the `private_key`. 6. Grant access via google calendar UI to the service account email address for each calendar you wish to manage. For a whole google apps domain, you can [delegate authority](https://developers.google.com/+/domains/authentication/delegation) An earlier version of Huginn used PKCS12 key files to authenticate. This will no longer work, you should generate a new JSON format keyfile, that will look something like: @@ -46,7 +46,7 @@ module Agents `google` A hash of configuration options for the agent. - `google` `service_account_email` - The authorised service account. + `google` `service_account_email` - The authorised service account email address. `google` `key_file` OR `google` `key` - The path to the JSON key file above, or the key itself (the value of `private_key`). [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) formatting is supported if you want to use a Credential. (E.g., `{% credential google_key %}`) @@ -56,6 +56,8 @@ module Agents A hash of event details. See the [Google Calendar API docs](https://developers.google.com/google-apps/calendar/v3/reference/events/insert) + The prior version Google's API expected keys like `dateTime` but in the latest version they expect snake case keys like `date_time`. + Example payload for trigger agent:
{
         "message": {
@@ -121,6 +123,8 @@ module Agents
           'agent_id' => event.agent_id,
           'event_id' => event.id
         }
+
+        calendar.cleanup!
       end
     end
   end
diff --git a/app/views/application/_upgrade_warning.html.erb b/app/views/application/_upgrade_warning.html.erb
index bd564a2a..b0ba0006 100644
--- a/app/views/application/_upgrade_warning.html.erb
+++ b/app/views/application/_upgrade_warning.html.erb
@@ -24,6 +24,25 @@ TWITTER_OAUTH_SECRET=<%= @twitter_oauth_secret %>
     <% end %>
   
 <% end -%>
+<% if @outdated_google_cal_agents && @outdated_google_cal_agents.length > 0 %>
+  
+    
+  
+<% end -%>
 <% if @outdated_docker_image_namespace %>
   
     
- Agent Configuration: `calendar_id` - The id the calendar you want to publish to. Typically your google account email address. Liquid formatting (e.g. `{{ cal_id }}`) is allowed here in order to extract the calendar_id from the incoming event. @@ -65,12 +64,10 @@ module Agents "summary": "Awesome event", "description": "An example event with text. Pro tip: DateTimes are in RFC3339", "start": { - "date_time": "2017-06-30T17:00:00-05:00", - "time_zone": "America/New_York" + "date_time": "2017-06-30T17:00:00-05:00" }, "end": { - "date_time": "2017-06-30T18:00:00-05:00", - "time_zone": "America/New_York" + "date_time": "2017-06-30T18:00:00-05:00" } } } @@ -112,9 +109,17 @@ module Agents incoming_events.each do |event| calendar = GoogleCalendar.new(interpolate_options(options, event), Rails.logger) + cal_message = event.payload["message"] + if cal_message["start"].present? && cal_message["start"]["dateTime"].present? && !cal_message["start"]["date_time"].present? + cal_message["start"]["date_time"] = cal_message["start"].delete "dateTime" + end + if cal_message["end"].present? && cal_message["end"]["dateTime"].present? && !cal_message["end"]["date_time"].present? + cal_message["end"]["date_time"] = cal_message["end"].delete "dateTime" + end + calendar_event = calendar.publish_as( interpolated(event)['calendar_id'], - event.payload["message"] + cal_message ) create_event :payload => { From 511bf14bac14051ec5194623742b962a4a04ce4c Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Fri, 7 Jul 2017 17:10:07 -0400 Subject: [PATCH 5/9] fix specs. the google calendar ones aren't actually using vcr so removing that --- ...should_publish_any_payload_it_receives.yml | 435 ------------------ .../google_calendar_publish_agent_spec.rb | 110 ++++- 2 files changed, 96 insertions(+), 449 deletions(-) delete mode 100644 spec/cassettes/Agents_GoogleCalendarPublishAgent/_receive/should_publish_any_payload_it_receives.yml diff --git a/spec/cassettes/Agents_GoogleCalendarPublishAgent/_receive/should_publish_any_payload_it_receives.yml b/spec/cassettes/Agents_GoogleCalendarPublishAgent/_receive/should_publish_any_payload_it_receives.yml deleted file mode 100644 index dc2a8eca..00000000 --- a/spec/cassettes/Agents_GoogleCalendarPublishAgent/_receive/should_publish_any_payload_it_receives.yml +++ /dev/null @@ -1,435 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest - body: - encoding: UTF-8 - string: '' - headers: - User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Linux/3.13.0-29-generic - (gzip) - Accept-Encoding: - - gzip - Content-Type: - - '' - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Expires: - - Sat, 28 Jun 2014 17:21:12 GMT - Date: - - Sat, 28 Jun 2014 17:16:12 GMT - Etag: - - '"C11OM5Qtr9122-scy_WeqND9D3o/icy_kevyvyjgCKjN6s1gb_9TUZs"' - Content-Type: - - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '11266' - Server: - - GSE - Age: - - '195' - Cache-Control: - - public, max-age=300, must-revalidate, no-transform - Alternate-Protocol: - - 443:quic - body: - encoding: ASCII-8BIT - string: !binary |- - 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 - 4Rn8/2/P/j8y14+toGwBAA== - http_version: - recorded_at: Sat, 28 Jun 2014 17:19:27 GMT -- request: - method: post - uri: https://accounts.google.com/o/oauth2/token - body: - encoding: ASCII-8BIT - string: grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIxMDI5OTM2OTY2MzI2LW5jamQ3Nzc2cGNzcGM5OGhzZzgyZ3NiNTZ0MzIxN2VmQGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2NvcGUiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9hdXRoL2NhbGVuZGFyIiwiYXVkIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL3Rva2VuIiwiZXhwIjoxNDAzOTc2MDI3LCJpYXQiOjE0MDM5NzU5MDd9.G2t_IqQofzzXKJAySGu4MulAybOp3BjptAk_tra7-ALy2pWu0jKw8XblP4T0YPgyMcbhcSJ_OhYl7Inmkxc3xhWsN-ZQDtacIyLv9roIRbvm5zCFKceJRISu2nZuIUTGTeoVuotPh6KRRvXIk1RW_Rc7L0eLeGTWn1USqdNwlfU - headers: - Cache-Control: - - no-store - Content-Type: - - application/x-www-form-urlencoded - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Content-Type: - - application/json; charset=utf-8 - Cache-Control: - - no-cache, no-store, max-age=0, must-revalidate - Pragma: - - no-cache - Expires: - - Fri, 01 Jan 1990 00:00:00 GMT - Date: - - Sat, 28 Jun 2014 17:19:28 GMT - Content-Disposition: - - attachment; filename="json.txt"; filename*=UTF-8''json.txt - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - 1; mode=block - Server: - - GSE - Alternate-Protocol: - - 443:quic - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: |- - { - "access_token" : "ya29.MgBhhNLHjzGOZBoAAADoyvaDO5G6GHmaxIYqa5EGZ5t8kL-unXKywIRYoYgQxw", - "token_type" : "Bearer", - "expires_in" : 3600 - } - http_version: - recorded_at: Sat, 28 Jun 2014 17:19:28 GMT -- request: - method: post - uri: https://www.googleapis.com/calendar/v3/calendars/sqv39gj35tc837gdns1g4d81cg@group.calendar.google.com/events?sendNotifications=true - body: - encoding: UTF-8 - string: '{"visibility":"default","summary":"Awesome event","description":"An - example event with text. Pro tip: DateTimes are in RFC3339","end":{"dateTime":"2014-10-02T11:00:00-05:00"},"start":{"dateTime":"2014-10-02T10:00:00-05:00"}}' - headers: - User-Agent: - - |- - Huginn/0.0.1 google-api-ruby-client/0.7.1 Linux/3.13.0-29-generic - (gzip) - Content-Type: - - application/json - Accept-Encoding: - - gzip - Authorization: - - Bearer ya29.MgBhhNLHjzGOZBoAAADoyvaDO5G6GHmaxIYqa5EGZ5t8kL-unXKywIRYoYgQxw - Cache-Control: - - no-store - Accept: - - "*/*" - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache, no-store, max-age=0, must-revalidate - Pragma: - - no-cache - Expires: - - Fri, 01 Jan 1990 00:00:00 GMT - Date: - - Sat, 28 Jun 2014 17:19:31 GMT - Etag: - - '"BZUCgRsJHN1b3Y4VmmLXiJzEzGI/MjgwNzk1MTk0MTk3MjAwMA"' - Content-Type: - - application/json; charset=UTF-8 - Content-Encoding: - - gzip - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - 1; mode=block - Server: - - GSE - Alternate-Protocol: - - 443:quic - Transfer-Encoding: - - chunked - body: - encoding: ASCII-8BIT - string: !binary |- - H4sIAAAAAAAAAH1T0U7bMBR971dY3ePW1IlLmlSaRkdXRkWqCZUxKl6Mfeu6 - iZ1gOw0E8e9LAh2btvFgKc49Pufce+zHHuqnUvP+BPUZzUBzat7BHrTrf2hK - 4KhoSzf9z+vLE3FhF1+X/i25Hn1X6vyHXNRf6tOzYbIT1bJO/WSV4maRZDet - kulNv6OQHbfd850RocF7mpa3dp9FjJfW5zLtQNZRV9rORK430ijg3f+tU9m5 - 1Glb2TpX2MlwWFWVJ/JcZOCxXA0Proed608g+UdG1inVC73UZxVXc8OvFjVX - 1eg6uPBZPU/plRWMzIOkzjTdJT4/TUZJzfX69KhOrhhez8T9dcCn66ozwQxQ - B10bAfZHAxwOgmjljyd+PAliD2O87nBlwf+LI9iLo/AZZ0ulqHlocdMKbK4A - vU6cg2VGFk7mugNoBPdUFdkLBlXSbZGDe+ehbyZHThYTNGtkV1KBRdQAkhpd - zE8IIfGr+9w0ZI891CSqqMxaZh8HcUzCOAxJEA402/HxeBwWzBYsjrZWRIGw - t0ehI4E/hs0xb+SzvADjCQtmLxlQxvJSuzaEfg89tVq5EVTLGv5Ws3d7Eosd - OXIsImPBtfXFiEc+E8fC5GXhHWL8LdrWfjMQaYuMPiypgpboaymk1ug8Z7Sd - UfMhnnEWsk0DcKaEFzfNpTLu4IS/zOhXOj4eYLLCuIlmgvF73GZ06AO6B/Hm - Of9f5+QJzS7PZm9f+OM/O2yM35WgWauA270B1TxIMPZgobQwgw0tM/faX++p - 9xPxx2cruwMAAA== - http_version: - recorded_at: Sat, 28 Jun 2014 17:19:31 GMT -recorded_with: VCR 2.9.2 diff --git a/spec/models/agents/google_calendar_publish_agent_spec.rb b/spec/models/agents/google_calendar_publish_agent_spec.rb index d12059f2..edc1a52a 100644 --- a/spec/models/agents/google_calendar_publish_agent_spec.rb +++ b/spec/models/agents/google_calendar_publish_agent_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Agents::GoogleCalendarPublishAgent, :vcr do +describe Agents::GoogleCalendarPublishAgent do let(:valid_params) do { 'expected_update_period_in_days' => "10", @@ -21,6 +21,20 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do end describe '#receive' do + let(:message) do + { + 'visibility' => 'default', + 'summary' => "Awesome event", + 'description' => "An example event with text. Pro tip: DateTimes are in RFC3339", + 'end' => { + 'date_time' => '2014-10-02T11:00:00-05:00' + }, + 'start' => { + 'date_time' => '2014-10-02T10:00:00-05:00' + } + } + end + let(:event) do _event = Event.new _event.agent = agents(:bob_manual_event_agent) @@ -30,19 +44,6 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do end let(:calendar_id) { 'sqv39gj35tc837gdns1g4d81cg@group.calendar.google.com' } - let(:message) do - { - 'visibility' => 'default', - 'summary' => "Awesome event", - 'description' => "An example event with text. Pro tip: DateTimes are in RFC3339", - 'end' => { - 'dateTime' => '2014-10-02T11:00:00-05:00' - }, - 'start' => { - 'dateTime' => '2014-10-02T10:00:00-05:00' - } - } - end let(:response_hash) do {"kind"=>"calendar#event", @@ -123,4 +124,85 @@ describe Agents::GoogleCalendarPublishAgent, :vcr do end end end + + describe '#receive old style event' do + let(:event) do + _event = Event.new + _event.agent = agents(:bob_manual_event_agent) + _event.payload = { 'message' => { + 'visibility' => 'default', + 'summary' => "Awesome event", + 'description' => "An example event with text. Pro tip: DateTimes are in RFC3339", + 'end' => { + 'dateTime' => '2014-10-02T11:00:00-05:00' + }, + 'start' => { + 'dateTime' => '2014-10-02T10:00:00-05:00' + } + } } + _event.save! + _event + end + + let(:calendar_id) { 'sqv39gj35tc837gdns1g4d81cg@group.calendar.google.com' } + let(:message) do + { + 'visibility' => 'default', + 'summary' => "Awesome event", + 'description' => "An example event with text. Pro tip: DateTimes are in RFC3339", + 'end' => { + 'date_time' => '2014-10-02T11:00:00-05:00' + }, + 'start' => { + 'date_time' => '2014-10-02T10:00:00-05:00' + } + } + end + + let(:response_hash) do + {"kind"=>"calendar#event", + "etag"=>"\"2908684044040000\"", + "id"=>"baz", + "status"=>"confirmed", + "html_link"=> + "https://calendar.google.com/calendar/event?eid=foobar", + "created"=>"2016-02-01T15:53:41.000Z", + "updated"=>"2016-02-01T15:53:42.020Z", + "summary"=>"Awesome event", + "description"=> + "An example event with text. Pro tip: DateTimes are in RFC3339", + "creator"=> + {"email"=> + "blah-foobar@developer.gserviceaccount.com"}, + "organizer"=> + {"email"=>calendar_id, + "display_name"=>"Huginn Location Log", + "self"=>true}, + "start"=>{"date_time"=>"2014-10-03T00:30:00+09:30"}, + "end"=>{"date_time"=>"2014-10-03T01:30:00+09:30"}, + "i_cal_uid"=>"blah@google.com", + "sequence"=>0, + "reminders"=>{"use_default"=>true} + } + end + + def setup_mock! + fake_interface = Object.new + mock(GoogleCalendar).new(agent.interpolate_options(agent.options), Rails.logger) { fake_interface } + mock(fake_interface).publish_as(calendar_id, message) { response_hash } + mock(fake_interface).cleanup! + end + + describe 'when the calendar_id is in the options' do + it 'should publish old style payload it receives' do + setup_mock! + + expect { + agent.receive([event]) + }.to change { agent.events.count }.by(1) + + expect(agent.events.last.payload).to eq({ "success" => true, "published_calendar_event" => response_hash, "agent_id" => event.agent_id, "event_id" => event.id }) + end + end + end end From 675700ac2d3221b0249b363ef8af677f3a8ef7ca Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Mon, 10 Jul 2017 11:20:08 -0400 Subject: [PATCH 6/9] update changelog / upgrade warning to be clearer about backward compatibility --- CHANGES.md | 1 + app/views/application/_upgrade_warning.html.erb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 324780e6..6fac06a4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ | DateOfChange | Changes | |----------------|--------------------------------------------------------------------------------------------------------------| +| Jul 10, 2017 | Update Google API Client. May break backwards compatibility for GoogleCalendarPublishAgent. [2047](https://github.com/huginn/huginn/pull/2047) | | Oct 17, 2016 | Normalize URL in `to_uri` and `uri_expand` liquid filters. | | Oct 06, 2016 | `RssAgent` is reimplemented migrating its underlying feed parser from FeedNormalizer to Feedjira. [1564](https://github.com/cantino/huginn/pull/1564) | | Oct 05, 2016 | Migrate to Rails 5. [1688](https://github.com/cantino/huginn/pull/1688) | diff --git a/app/views/application/_upgrade_warning.html.erb b/app/views/application/_upgrade_warning.html.erb index b0ba0006..8c2cb2c5 100644 --- a/app/views/application/_upgrade_warning.html.erb +++ b/app/views/application/_upgrade_warning.html.erb @@ -31,6 +31,8 @@ TWITTER_OAUTH_SECRET=<%= @twitter_oauth_secret %> Warning! Your Google Calendar Publish Agents are using an outdated version of Google Auth. You need to update the agent configuration, possibly with a new keyfile from Google for it to continue to work.
PKCS12 key files (`.p12`) are no longer supported. Instead use RSA private keys. Edit the agents to see the updated instructions. The `google.key_secret` option is no longer needed, please remove it. +
+ The format of parameters in events passed to the agent have also changed. Parameters now are expected in underscore_case instead of camelCase (to match Ruby convention). Please update upstream agents that send events to the calendar agent.

Outdated agents: From b4fb6e2e276cc8c5908f7d3f8e4257d24b298ca1 Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Mon, 10 Jul 2017 11:51:04 -0400 Subject: [PATCH 7/9] put calendar cleanup in ensure block --- .../agents/google_calendar_publish_agent.rb | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/app/models/agents/google_calendar_publish_agent.rb b/app/models/agents/google_calendar_publish_agent.rb index 773d741a..4acfcde3 100644 --- a/app/models/agents/google_calendar_publish_agent.rb +++ b/app/models/agents/google_calendar_publish_agent.rb @@ -107,29 +107,31 @@ module Agents def receive(incoming_events) require 'google_calendar' incoming_events.each do |event| - calendar = GoogleCalendar.new(interpolate_options(options, event), Rails.logger) + begin + calendar = GoogleCalendar.new(interpolate_options(options, event), Rails.logger) - cal_message = event.payload["message"] - if cal_message["start"].present? && cal_message["start"]["dateTime"].present? && !cal_message["start"]["date_time"].present? - cal_message["start"]["date_time"] = cal_message["start"].delete "dateTime" + cal_message = event.payload["message"] + if cal_message["start"].present? && cal_message["start"]["dateTime"].present? && !cal_message["start"]["date_time"].present? + cal_message["start"]["date_time"] = cal_message["start"].delete "dateTime" + end + if cal_message["end"].present? && cal_message["end"]["dateTime"].present? && !cal_message["end"]["date_time"].present? + cal_message["end"]["date_time"] = cal_message["end"].delete "dateTime" + end + + calendar_event = calendar.publish_as( + interpolated(event)['calendar_id'], + cal_message + ) + + create_event :payload => { + 'success' => true, + 'published_calendar_event' => calendar_event, + 'agent_id' => event.agent_id, + 'event_id' => event.id + } + ensure + calendar.cleanup! end - if cal_message["end"].present? && cal_message["end"]["dateTime"].present? && !cal_message["end"]["date_time"].present? - cal_message["end"]["date_time"] = cal_message["end"].delete "dateTime" - end - - calendar_event = calendar.publish_as( - interpolated(event)['calendar_id'], - cal_message - ) - - create_event :payload => { - 'success' => true, - 'published_calendar_event' => calendar_event, - 'agent_id' => event.agent_id, - 'event_id' => event.id - } - - calendar.cleanup! end end end From 34b56885c8683d54a12fde3e6d0fb1343dc48168 Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Sat, 22 Jul 2017 16:13:07 -0400 Subject: [PATCH 8/9] Use a wrapper class method to invoke GoogleCalendar, per knu's PR feedback --- app/models/agents/google_calendar_publish_agent.rb | 5 +---- lib/google_calendar.rb | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/agents/google_calendar_publish_agent.rb b/app/models/agents/google_calendar_publish_agent.rb index 4acfcde3..680fa620 100644 --- a/app/models/agents/google_calendar_publish_agent.rb +++ b/app/models/agents/google_calendar_publish_agent.rb @@ -107,8 +107,7 @@ module Agents def receive(incoming_events) require 'google_calendar' incoming_events.each do |event| - begin - calendar = GoogleCalendar.new(interpolate_options(options, event), Rails.logger) + GoogleCalendar.open(interpolate_options(options, event), Rails.logger) do |calendar| cal_message = event.payload["message"] if cal_message["start"].present? && cal_message["start"]["dateTime"].present? && !cal_message["start"]["date_time"].present? @@ -129,8 +128,6 @@ module Agents 'agent_id' => event.agent_id, 'event_id' => event.id } - ensure - calendar.cleanup! end end end diff --git a/lib/google_calendar.rb b/lib/google_calendar.rb index 7212ac4a..2c80526c 100644 --- a/lib/google_calendar.rb +++ b/lib/google_calendar.rb @@ -29,6 +29,13 @@ class GoogleCalendar @logger.debug @calendar.inspect end + def self.open(*args, &block) + instance = new(*args) + block.call(instance) + ensure + instance.cleanup! + end + def auth_as @authorization.fetch_access_token! @calendar.authorization = @authorization From 9a17bc68b9c0a29f0eea48b3a379d66a3d108d0a Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Tue, 1 Aug 2017 08:37:59 -0400 Subject: [PATCH 9/9] use of_type --- app/controllers/application_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b2354474..a56aa61c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -72,7 +72,7 @@ class ApplicationController < ActionController::Base end def outdated_google_auth_check - @outdated_google_cal_agents = current_user.agents.where("type like 'Agents::GoogleCalendarPublishAgent'").select do |agent| + @outdated_google_cal_agents = current_user.agents.of_type('Agents::GoogleCalendarPublishAgent').select do |agent| agent.options['google']['key_secret'].present? end end