diff --git a/org-gcal.el b/org-gcal.el index 7835f9d..138d017 100644 --- a/org-gcal.el +++ b/org-gcal.el @@ -5,7 +5,7 @@ ;; Version: 0.3 ;; Maintainer: Raimon Grau ;; Copyright (C) :2014 myuhe all rights reserved. -;; Package-Requires: ((request "20190901") (request-deferred "20181129") (alert) (persist) (emacs "26") (org "9.3")) +;; Package-Requires: ((request "20190901") (request-deferred "20181129") (alert) (persist) (oauth2-auto "0.1") (emacs "26") (org "9.3")) ;; Keywords: convenience, ;; This program is free software; you can redistribute it and/or modify @@ -35,7 +35,8 @@ (require 'alert) (require 'json) -(require 'request-deferred) +(require 'aio) +(require 'oauth2-auto) (require 'ol) (require 'org) (require 'org-archive) @@ -45,6 +46,7 @@ (require 'org-id) (require 'parse-time) (require 'persist) +(require 'request-deferred) (require 'cl-lib) (require 'rx) (require 'subr-x) @@ -299,15 +301,6 @@ See: https://developers.google.com/calendar/v3/reference/events/insert." :group 'org-gcal :type 'string) -(defconst org-gcal-auth-url "https://accounts.google.com/o/oauth2/auth" - "Google OAuth2 server URL.") - -(defconst org-gcal-token-url "https://www.googleapis.com/oauth2/v3/token" - "Google OAuth2 server URL.") - -(defconst org-gcal-resource-url "https://www.googleapis.com/auth/calendar" - "URL used to request access to calendar resources.") - (defun org-gcal-events-url (calendar-id) "URL used to request access to events on calendar CALENDAR-ID." (format "https://www.googleapis.com/calendar/v3/calendars/%s/events" @@ -360,7 +353,6 @@ SKIP-EXPORT. Set SILENT to non-nil to inhibit notifications." (user-error "org-gcal sync locked. If a previous sync has failed, call ‘org-gcal--sync-unlock’ to reset the lock and try again.")) (org-gcal--sync-lock) (org-generic-id-update-id-locations org-gcal-entry-id-property) - (org-gcal--ensure-token) (when org-gcal-auto-archive (dolist (i org-gcal-fetch-file-alist) (with-current-buffer @@ -532,10 +524,10 @@ CALENDAR-ID-FILE is a cons in ‘org-gcal-fetch-file-alist’, for which see." :type "GET" :headers `(("Accept" . "application/json") - ("Authorization" . ,(format "Bearer %s" (org-gcal--get-access-token)))) + ("Authorization" . ,(format "Bearer %s" (org-gcal--get-access-token calendar-id)))) :params (append - `(("access_token" . ,(org-gcal--get-access-token)) + `(("access_token" . ,(org-gcal--get-access-token calendar-id)) ("singleEvents" . "True")) (when org-gcal-local-timezone `(("timeZone" . ,org-gcal-local-timezone))) (seq-let [expires sync-token] @@ -565,10 +557,10 @@ CALENDAR-ID-FILE is a cons in ‘org-gcal-fetch-file-alist’, for which see." :type "GET" :headers `(("Accept" . "application/json") - ("Authorization" . ,(format "Bearer %s" (org-gcal--get-access-token)))) + ("Authorization" . ,(format "Bearer %s" (org-gcal--get-access-token calendar-id)))) :params (append - `(("access_token" . ,(org-gcal--get-access-token)) + `(("access_token" . ,(org-gcal--get-access-token calendar-id)) ("timeMin" . ,(org-gcal--format-time2iso up-time)) ("timeMax" . ,(org-gcal--format-time2iso down-time))) (when page-token `(("pageToken" . ,page-token)))) @@ -599,7 +591,7 @@ objects for further processing." "Received HTTP 401" "OAuth token expired. Now trying to refresh-token") (deferred:$ - (org-gcal--refresh-token) + (org-gcal--refresh-token calendar-id) (deferred:nextc it (lambda (_unused) (funcall retry-fn))))) @@ -800,7 +792,6 @@ to “org”." (when org-gcal--sync-lock (user-error "org-gcal sync locked. If a previous sync has failed, call ‘org-gcal--sync-unlock’ to reset the lock and try again.")) (org-gcal--sync-lock) - (org-gcal--ensure-token) (let* ((name (or (buffer-file-name) (buffer-name)))) (deferred:try @@ -1219,7 +1210,6 @@ If SKIP-EXPORT is not nil, don’t overwrite the event on the server. For valid values of EXISTING-MODE see ‘org-gcal-managed-post-at-point-update-existing'." (interactive) - (org-gcal--ensure-token) (save-excursion ;; Post entry at point in org-agenda buffer. (when (eq major-mode 'org-agenda-mode) @@ -1329,7 +1319,6 @@ If called with prefix or with CLEAR-GCAL-INFO non-nil, will clear calendar info from the entry even if deleting the event from the server fails. Use this to delete calendar info from events on calendars you no longer have access to." (interactive "P") - (org-gcal--ensure-token) (save-excursion ;; Delete entry at point in org-agenda buffer. (when (eq major-mode 'org-agenda-mode) @@ -1383,92 +1372,21 @@ delete calendar info from events on calendars you no longer have access to." (deferred:succeed nil)))) (deferred:succeed nil))))) -(defun org-gcal-request-authorization () - "Request OAuth authorization at AUTH-URL by launching `browse-url'. - CLIENT-ID is the client id provided by the provider. - It returns the code provided by the service." - (let* ((gcal-auth-url - (concat org-gcal-auth-url - "?client_id=" (url-hexify-string org-gcal-client-id) - "&response_type=code" - "&redirect_uri=" (url-hexify-string "urn:ietf:wg:oauth:2.0:oob") - "&scope=" (url-hexify-string org-gcal-resource-url))) - (prompt - (format - "Please visit (if it doesn't open automatically): %s\n\nEnter the code your browser displayed:" - gcal-auth-url))) - (browse-url gcal-auth-url) - (read-string prompt))) - -(defun org-gcal-request-token () - "Refresh OAuth access at TOKEN-URL. - - Returns a ‘deferred’ object that can be used to wait for completion." - (interactive) - (deferred:$ - (request-deferred - org-gcal-token-url - :type "POST" - :data `(("client_id" . ,org-gcal-client-id) - ("client_secret" . ,org-gcal-client-secret) - ("code" . ,(org-gcal-request-authorization)) - ("redirect_uri" . "urn:ietf:wg:oauth:2.0:oob") - ("grant_type" . "authorization_code")) - :parser 'org-gcal--json-read) - (deferred:nextc it - (lambda (response) - (let - ((data (request-response-data response)) - (status-code (request-response-status-code response)) - (error-thrown (request-response-error-thrown response))) - (cond - ;; If there is no network connectivity, the response will not - ;; include a status code. - ((eq status-code nil) - (org-gcal--notify - "Got Error" - "Could not contact remote service. Please check your network connectivity.") - (error "Network connectivity issue %s: %s" status-code error-thrown)) - ;; Generic error-handler meant to provide useful information about - ;; failure cases not otherwise explicitly specified. - ((not (eq error-thrown nil)) - (org-gcal--notify - (concat "Status code: " (number-to-string status-code)) - (pp-to-string error-thrown)) - (error "Got error %S: %S" status-code error-thrown)) - ;; Fetch was successful. - (t - (when data - (setq org-gcal-token-plist data) - (org-gcal--save-sexp data org-gcal-token-file)) - (deferred:succeed nil)))))))) - -(defun org-gcal--refresh-token () +(defun org-gcal--get-access-token (calendar-id) + "Return the access token for CALENDAR-ID." + (aio-wait-for + (oauth2-auto-access-token calendar-id 'org-gcal))) + +(defun org-gcal--refresh-token (calendar-id) "Refresh OAuth access and return the new access token as a deferred object." - (deferred:$ - (request-deferred - org-gcal-token-url - :type "POST" - :data `(("client_id" . ,org-gcal-client-id) - ("client_secret" . ,org-gcal-client-secret) - ("refresh_token" . ,(org-gcal--get-refresh-token)) - ("grant_type" . "refresh_token")) - :parser 'org-gcal--json-read) - (deferred:nextc it - (lambda (response) - (let ((data (request-response-data response)) - (status-code (request-response-status-code response)) - (error-thrown (request-response-error-thrown response))) - (cond - ((eq error-thrown nil) - (plist-put org-gcal-token-plist - :access_token - (plist-get data :access_token)) - (org-gcal--save-sexp org-gcal-token-plist org-gcal-token-file) - (let ((_token (plist-get org-gcal-token-plist :access_token))) - (deferred:succeed nil))) - (t - (error "Got error %S: %S" status-code error-thrown)))))))) + ;; FIXME: For now, we just synchronously wait for the refresh. Once the + ;; project has been rewritten to use aio + ;; (https://github.com/kidd/org-gcal.el/issues/191), we can wait for this + ;; asynchronously as well. + (let ((token + (aio-wait-for + (oauth2-auto-access-token calendar-id 'org-gcal)))) + (deferred:succeed token))) ;;;###autoload (defun org-gcal-sync-tokens-clear () @@ -1490,7 +1408,7 @@ delete calendar info from events on calendars you no longer have access to." ; Check if headline is managed by `org-gcal', and hasn't been archived ; yet. Only in that case, potentially archive. (when (and (assoc "ORG-GCAL-MANAGED" properties) - (not (assoc "ARCHIVE_TIME" properties))) + (not (assoc "ARCHIVE_TIME" properties))) ; Go to beginning of line to parse the headline (beginning-of-line) @@ -1549,30 +1467,6 @@ delete calendar info from events on calendars you no longer have access to." (decode-coding-string (buffer-substring-no-properties (point-min) (point-max)) 'utf-8)))) -(defun org-gcal--get-refresh-token () - (if org-gcal-token-plist - (plist-get org-gcal-token-plist :refresh_token) - (progn - (if (file-exists-p org-gcal-token-file) - (progn - (with-temp-buffer (insert-file-contents org-gcal-token-file) - (plist-get (plist-get (read (buffer-string)) :token) :refresh_token))) - (org-gcal--notify - (concat org-gcal-token-file " does not exist.") - (concat "Please create " org-gcal-token-file " before proceeding.")))))) - -(defun org-gcal--get-access-token () - (if org-gcal-token-plist - (plist-get org-gcal-token-plist :access_token) - (progn - (if (file-exists-p org-gcal-token-file) - (progn - (with-temp-buffer (insert-file-contents org-gcal-token-file) - (plist-get (plist-get (read (buffer-string)) :token) :access_token))) - (org-gcal--notify - (concat org-gcal-token-file " is not exists") - (concat "Make " org-gcal-token-file)))))) - (defun org-gcal--safe-substring (string from &optional to) "Call the `substring' function safely. No errors will be returned for out of range values of FROM and @@ -1912,7 +1806,7 @@ access token A-TOKEN is not specified, it is loaded from the token file. Returns a ‘deferred’ function that on success returns a ‘request-response‘ object." - (let ((a-token (org-gcal--get-access-token))) + (let ((a-token (org-gcal--get-access-token calendar-id))) (deferred:$ (request-deferred (concat @@ -1943,7 +1837,7 @@ object." "Received HTTP 401" "OAuth token expired. Now trying to refresh token.") (deferred:$ - (org-gcal--refresh-token) + (org-gcal--refresh-token calendar-id) (deferred:nextc it (lambda (_unused) (org-gcal--get-event calendar-id event-id))))) @@ -1976,7 +1870,7 @@ Returns a ‘deferred’ object that can be used to wait for completion." (etime (org-gcal--param-date end)) (stime-alt (org-gcal--param-date-alt start)) (etime-alt (org-gcal--param-date-alt end)) - (a-token (or a-token (org-gcal--get-access-token)))) + (a-token (or a-token (org-gcal--get-access-token calendar-id)))) (deferred:try (deferred:$ (apply @@ -2040,7 +1934,7 @@ Returns a ‘deferred’ object that can be used to wait for completion." "Received HTTP 401" "OAuth token expired. Now trying to refresh-token") (deferred:$ - (org-gcal--refresh-token) + (org-gcal--refresh-token calendar-id) (deferred:nextc it (lambda (_unused) (org-gcal--post-event start end smry loc source desc calendar-id @@ -2107,7 +2001,7 @@ If ETAG is provided, it is used to retrieve the event data from the server and overwrite the event at MARKER if the event has changed on the server. Returns a ‘deferred’ object that can be used to wait for completion." - (let ((a-token (or a-token (org-gcal--get-access-token)))) + (let ((a-token (or a-token (org-gcal--get-access-token calendar-id)))) (deferred:try (deferred:$ (request-deferred @@ -2147,7 +2041,7 @@ Returns a ‘deferred’ object that can be used to wait for completion." "Received HTTP 401" "OAuth token expired. Now trying to refresh-token") (deferred:$ - (org-gcal--refresh-token) + (org-gcal--refresh-token calendar-id) (deferred:nextc it (lambda (_unused) (org-gcal--delete-event calendar-id event-id @@ -2224,22 +2118,6 @@ Returns a ‘deferred’ object that can be used to wait for completion." (with-eval-after-load 'org-refile (add-hook 'org-after-refile-insert-hook 'org-gcal--refile-post)) -(defun org-gcal--ensure-token () - "Ensure that access, refresh, and sync token variables in expected state." - (unless (org-gcal--sync-tokens-valid) - (persist-load 'org-gcal--sync-tokens) - (unless (org-gcal--sync-tokens-valid) - (org-gcal-sync-tokens-clear))) - (cond - (org-gcal-token-plist t) - ((and (file-exists-p org-gcal-token-file) - (ignore-errors - (setq org-gcal-token-plist - (with-temp-buffer - (insert-file-contents org-gcal-token-file) - (plist-get (read (current-buffer)) :token))))) t) - (t (deferred:sync! (org-gcal-request-token))))) - (defun org-gcal--sync-tokens-valid () "Is ‘org-gcal--sync-tokens’ in a valid format?" (and (listp org-gcal--sync-tokens) @@ -2281,6 +2159,24 @@ non-nil." (plist-get plst :year)))) +(defun org-gcal-reload-client-id-secret () + "Setup OAuth2 authentication after setting client ID and secret." + (interactive) + (add-to-list + 'oauth2-auto-additional-providers-alist + `(org-gcal + (authorize_url . "https://accounts.google.com/o/oauth2/auth") + (token_url . "https://oauth2.googleapis.com/token") + (scope . "https://www.googleapis.com/auth/calendar") + (client_id . ,org-gcal-client-id) + (client_secret . ,org-gcal-client-secret)))) + +(if (and org-gcal-client-id org-gcal-client-secret) + (org-gcal-reload-client-id-secret) + ;; Don’t print warning during tests. + (unless noninteractive + (warn "org-gcal: must set ‘org-gcal-client-id’ and ‘org-gcal-client-secret’ for this package to work. Please run ‘org-gcal-reload-client-id-secret’ after setting these variables."))) + (provide 'org-gcal) ;;; org-gcal.el ends here diff --git a/test/org-gcal-test.el b/test/org-gcal-test.el index e600e55..414e84c 100644 --- a/test/org-gcal-test.el +++ b/test/org-gcal-test.el @@ -26,6 +26,13 @@ ;;; Code: +;; Must set these variables before loading the package, but don’t reset them if +;; they’re already set. +(unless (and (boundp 'org-gcal-client-id) org-gcal-client-id + (boundp 'org-gcal-client-secret) org-gcal-client-secret) + (setq org-gcal-client-id "test_client_id" + org-gcal-client-secret "test_client_secret")) + (require 'org-gcal) (require 'cl-lib) (require 'el-mock) @@ -588,7 +595,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -631,7 +639,8 @@ Original second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (stub request-deferred => (deferred:succeed (make-request-response @@ -697,7 +706,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (y-or-n-p *) => nil) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" @@ -734,7 +744,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -768,7 +779,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (y-or-n-p *) => nil) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" @@ -805,7 +817,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -842,7 +855,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -875,7 +889,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -910,15 +925,16 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) - (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" - "My event summary" "Foobar's desk" - `((url . "https://google.com") (title . "Google")) - "My event description\n\nSecond paragraph" - "foo@foobar.com" - * "opaque" nil nil - * * *)) - (org-gcal-post-at-point))) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) + (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" + "My event summary" "Foobar's desk" + `((url . "https://google.com") (title . "Google")) + "My event description\n\nSecond paragraph" + "foo@foobar.com" + * "opaque" nil nil + * * *)) + (org-gcal-post-at-point))) (org-gcal-test--with-temp-buffer "\ * My event summary @@ -940,15 +956,16 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) - (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" - "My event summary" "Foobar's desk" - `((url . "https://google.com") (title . "Google")) - "My event description\n\nSecond paragraph" - "foo@foobar.com" - * "opaque" nil nil - * * *)) - (org-gcal-post-at-point)))) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) + (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-06T21:00:00Z" + "My event summary" "Foobar's desk" + `((url . "https://google.com") (title . "Google")) + "My event description\n\nSecond paragraph" + "foo@foobar.com" + * "opaque" nil nil + * * *)) + (org-gcal-post-at-point)))) (ert-deftest org-gcal-test--post-at-point-no-properties () "Verify that ‘org-gcal-post-to-point’ fills in entries with no relevant @@ -963,7 +980,8 @@ org-gcal properties with sane default values." (stub read-from-minibuffer => "4:00") (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00+0000" "2019-10-06T21:00:00+0000" "My event summary" nil nil nil @@ -986,7 +1004,8 @@ CLOCK: [2019-06-06 Thu 17:00]--[2019-06-06 Thu 18:00] => 1:00 (stub org-read-date => (encode-time 0 0 17 6 10 2019 nil nil t)) (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (cl-letf (((symbol-function #'read-from-minibuffer) (lambda (_p initial-contents) initial-contents))) @@ -1003,7 +1022,7 @@ CLOCK: [2019-06-06 Thu 17:00]--[2019-06-06 Thu 18:00] => 1:00 an event ID is not." :expected-result :failed (org-gcal-test--with-temp-buffer - "\ + "\ * My event summary :PROPERTIES: :LOCATION: Foobar's desk @@ -1019,12 +1038,13 @@ My event description Second paragraph :END: " - (with-mock - (stub org-gcal--time-zone => '(0 "UTC")) - (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) - (stub request-deferred => (deferred:succeed nil)) - (org-gcal-post-at-point)))) + (with-mock + (stub org-gcal--time-zone => '(0 "UTC")) + (stub org-generic-id-add-location => nil) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) + (stub request-deferred => (deferred:succeed nil)) + (org-gcal-post-at-point)))) (ert-deftest org-gcal-test--post-at-point-time-date-range () "Verify that entry with a time/date range for its timestamp is parsed by @@ -1050,7 +1070,8 @@ Second paragraph (with-mock (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (mock (org-gcal--post-event "2019-10-06T17:00:00Z" "2019-10-07T21:00:00Z" "My event summary" "Foobar's desk" `((url . "https://google.com") (title . "Google")) @@ -1091,7 +1112,8 @@ Second paragraph (let ((deferred:debug t)) (stub org-gcal--time-zone => '(0 "UTC"))) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (stub y-or-n-p => t) (stub alert => t) (stub request-deferred => @@ -1113,7 +1135,8 @@ Second paragraph (let ((deferred:debug t)) (stub org-gcal--time-zone => '(0 "UTC")) (stub org-generic-id-add-location => nil) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (stub y-or-n-p => t) (stub request-deferred => (deferred:succeed @@ -1130,7 +1153,8 @@ Second paragraph (let ((deferred:debug t) (org-gcal-remove-api-cancelled-events t)) (stub org-gcal--time-zone => '(0 "UTC")) - (stub org-gcal-request-token => (deferred:succeed nil)) + (stub org-gcal--get-access-token => "my_access_token") + (stub org-gcal--refresh-token => (deferred:succeed "test_access_token")) (stub y-or-n-p => t) (stub request-deferred => (deferred:succeed