讀取Google 行事曆

啟動Google Calendar API

  • 使用此連結 this wizard 至Google Developers Console 建立或選取專案並啟動API. 點選 前往「憑證」
  • 在 將憑證新稱至您的專案(On the Add credentials to your project page)頁面,點選取消
  • 在憑證頁面上方,點選OAuth同意頁籤(OAuth consent)選取電子郵件地址(Email address)、輸入向使用者顯示的產品名稱(Product name)及其他相關訊息後,點選儲存。
  • 選擇憑證頁籤(Credentials),點選建立憑證按鍵(Create credentials button)選擇OAuth用戶端ID(OAuth client ID)
  • 應用程式類型,請選擇其他(Other),輸入名稱(例如:”Google Calendar API Quickstart),點選建立按鍵
  • 點選確定關閉視窗
  • 在剛剛建立的ID後方功能列,點選下載JSON (Download JSON)
  • 將檔案搬移到專案目錄下,並更名為:client_secret.json

使用函數庫

go get -u google.golang.org/api/calendar/v3
go get -u golang.org/x/oauth2/...

簡易程式碼 quickstart.go

package main

import (
  "encoding/json"
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
  "net/url"
  "os"
  "os/user"
  "path/filepath"
  "time"

  "golang.org/x/net/context"
  "golang.org/x/oauth2"
  "golang.org/x/oauth2/google"
  "google.golang.org/api/calendar/v3"
)

// getClient uses a Context and Config to retrieve a Token
// then generate a Client. It returns the generated Client.
func getClient(ctx context.Context, config *oauth2.Config) *http.Client {
  cacheFile, err := tokenCacheFile()
  if err != nil {
    log.Fatalf("Unable to get path to cached credential file. %v", err)
  }
  tok, err := tokenFromFile(cacheFile)
  if err != nil {
    tok = getTokenFromWeb(config)
    saveToken(cacheFile, tok)
  }
  return config.Client(ctx, tok)
}

// getTokenFromWeb uses Config to request a Token.
// It returns the retrieved Token.
func getTokenFromWeb(config *oauth2.Config) *oauth2.Token {
  authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
  fmt.Printf("Go to the following link in your browser then type the "+
    "authorization code: \n%v\n", authURL)

  var code string
  if _, err := fmt.Scan(&code); err != nil {
    log.Fatalf("Unable to read authorization code %v", err)
  }

  tok, err := config.Exchange(oauth2.NoContext, code)
  if err != nil {
    log.Fatalf("Unable to retrieve token from web %v", err)
  }
  return tok
}

// tokenCacheFile generates credential file path/filename.
// It returns the generated credential path/filename.
func tokenCacheFile() (string, error) {
  usr, err := user.Current()
  if err != nil {
    return "", err
  }
  tokenCacheDir := filepath.Join(usr.HomeDir, ".credentials")
  os.MkdirAll(tokenCacheDir, 0700)
  return filepath.Join(tokenCacheDir,
    url.QueryEscape("calendar-go-quickstart.json")), err
}

// tokenFromFile retrieves a Token from a given file path.
// It returns the retrieved Token and any read error encountered.
func tokenFromFile(file string) (*oauth2.Token, error) {
  f, err := os.Open(file)
  if err != nil {
    return nil, err
  }
  t := &oauth2.Token{}
  err = json.NewDecoder(f).Decode(t)
  defer f.Close()
  return t, err
}

// saveToken uses a file path to create a file and store the
// token in it.
func saveToken(file string, token *oauth2.Token) {
  fmt.Printf("Saving credential file to: %s\n", file)
  f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
  if err != nil {
    log.Fatalf("Unable to cache oauth token: %v", err)
  }
  defer f.Close()
  json.NewEncoder(f).Encode(token)
}

func main() {
  ctx := context.Background()

  b, err := ioutil.ReadFile("client_secret.json")
  if err != nil {
    log.Fatalf("Unable to read client secret file: %v", err)
  }

  // If modifying these scopes, delete your previously saved credentials
  // at ~/.credentials/calendar-go-quickstart.json
  config, err := google.ConfigFromJSON(b, calendar.CalendarReadonlyScope)
  if err != nil {
    log.Fatalf("Unable to parse client secret file to config: %v", err)
  }
  client := getClient(ctx, config)

  srv, err := calendar.New(client)
  if err != nil {
    log.Fatalf("Unable to retrieve calendar Client %v", err)
  }

  t := time.Now().Format(time.RFC3339)
  events, err := srv.Events.List("primary").ShowDeleted(false).
    SingleEvents(true).TimeMin(t).MaxResults(10).OrderBy("startTime").Do()
  if err != nil {
    log.Fatalf("Unable to retrieve next ten of the user's events. %v", err)
  }

  fmt.Println("Upcoming events:")
  if len(events.Items) > 0 {
    for _, i := range events.Items {
      var when string
      // If the DateTime is an empty string the Event is an all-day Event.
      // So only Date is available.
      if i.Start.DateTime != "" {
        when = i.Start.DateTime
      } else {
        when = i.Start.Date
      }
      fmt.Printf("%s (%s)\n", i.Summary, when)
    }
  } else {
    fmt.Printf("No upcoming events found.\n")
  }

}

第一次執行時會產生網址,請將這個網址貼到瀏覽器上,並同意授權。將網頁上的授權碼貼到command line後,就可以進行資料讀取。若要透過web授權,可參考此篇文章

改用web認證步驟

  • Open the Credentials page in the API Console.
  • Click Create credentials > OAuth client ID.
  • Complete the form. Set the application type to Web application. Applications that use languages and frameworks like PHP, Java, Python, Ruby, and .NET must specify authorized redirect URIs. The redirect URIs are the endpoints to which the OAuth 2.0 server can send responses.
  • 建議可以依照此頁面指示建立專屬的認證頁面

For testing, you can specify URIs that refer to the local machine, such as http://localhost:8080. With that in mind, please note that all of the examples in this document use http://localhost:8080 as the redirect URI.

參考資料

行事曆相關工具