// postGerritMessage posts a message to the code review thread for the given // Commit. func postGerritMessage(c appengine.Context, com *Commit, message string) error { if appengine.IsDevAppServer() { c.Infof("Skiping update of Gerrit review for %v with message: %v", com, message) return nil } // Get change ID using commit hash. resp, err := urlfetch.Client(c).Get("https://go-review.googlesource.com/r/" + com.Hash) if err != nil { return fmt.Errorf("lookup %v: contacting Gerrit %v", com.Hash, err) } resp.Body.Close() if resp.Request == nil || resp.Request.URL == nil { return fmt.Errorf("lookup %s: missing request info in http response", com.Hash) } frag := resp.Request.URL.Fragment if !strings.HasPrefix(frag, "/c/") || !strings.HasSuffix(frag, "/") { return fmt.Errorf("lookup %s: unexpected URL fragment: #%s", com.Hash, frag) } id := frag[len("/c/") : len(frag)-len("/")] // Prepare request. msg := struct { Message string `json:"message"` }{message} data, err := json.Marshal(&msg) if err != nil { return fmt.Errorf("marshalling message: %v", err) } req, err := http.NewRequest("POST", "https://go-review.googlesource.com/a/changes/"+id+"/revisions/current/review", bytes.NewReader(data)) if err != nil { return fmt.Errorf("preparing message: %v", err) } req.Header.Set("Content-Type", "application/json") req.SetBasicAuth(Config(c, "GerritUsername"), Config(c, "GerritPassword")) // Make request. resp, err = urlfetch.Client(c).Do(req) if err != nil { return fmt.Errorf("posting message: %v", err) } body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { return fmt.Errorf("reading response body: %v", err) } if resp.StatusCode != http.StatusOK { return fmt.Errorf("posting message: %s\n%s", resp.Status, body) } return nil }
func RemoveFromSearchIndex(c appengine.Context, nut *Nut) (err error) { m := make(map[string]interface{}) m["Nut"] = nut b, err := json.Marshal(m) if err != nil { return } req, err := http.NewRequest("POST", searchRemoveUrl.String(), bytes.NewReader(b)) if err != nil { return } req.Header.Set("Content-Type", "application/json") client := urlfetch.Client(c) res, err := client.Do(req) if err == nil { res.Body.Close() if res.StatusCode != 204 { err = fmt.Errorf("%s -> %d", searchRemoveUrl.String(), res.StatusCode) } } return }
func ShorterUrl(c appengine.Context, longUrl string) string { c.Debugf("ShorterUrl long url: %s", longUrl) conf, err := GetTwitterConf(c) if err != nil { c.Errorf("ShorterUrl failed to load TwitterConf: %v", err) return "" } url := "https://www.googleapis.com/urlshortener/v1/url?key=" + conf.GoogleShortUrlApiKey jsonInput, err := json.Marshal(map[string]string{"longUrl": longUrl}) if err != nil { c.Errorf("ShorterUrl failed to marshal json: %v", err) return "" } c.Debugf("body: %s", string(jsonInput)) body := bytes.NewBuffer(jsonInput) request, _ := http.NewRequest("POST", url, body) request.Header.Set("Content-Type", "application/json") client := urlfetch.Client(c) response, err := client.Do(request) if err != nil { c.Errorf("ShorterUrl failed to api call: %v", err) return "" } jsonVal, err2 := ioutil.ReadAll(response.Body) if err2 != nil { c.Errorf("ShorterUrl failed to read result: %v", err) return "" } c.Debugf("ShorterUrl response: %v", string(jsonVal)) var result UrlResult json.Unmarshal(jsonVal, &result) c.Debugf("ShorterUrl %s", result.Id) return result.Id }
// signout Revokes access for the user and removes the associated credentials from the datastore. func signoutHandler(w http.ResponseWriter, r *http.Request) error { if r.Method != "POST" { return nil } c := appengine.NewContext(r) userId, err := userID(r) if err != nil { return fmt.Errorf("Unable to retrieve user ID: %s", err) } if userId == "" { http.Redirect(w, r, "/auth", http.StatusFound) return nil } t := authTransport(c, userId) if t == nil { http.Redirect(w, r, "/auth", http.StatusFound) return nil } client := urlfetch.Client(c) _, err = client.Get(fmt.Sprintf(revokeEndpointFmt, t.Token.RefreshToken)) if err != nil { return fmt.Errorf("Unable to revoke token: %s", err) } storeUserID(w, r, "") deleteCredential(c, userId) http.Redirect(w, r, "/", http.StatusFound) return nil }
// fetch fetches a meetup group given its id from using the meetup API // docs for the API: http://www.meetup.com/meetup_api/docs/ func fetch(c appengine.Context, id string) (*Group, error) { const ( apiKey = "obtain your apikey from https://secure.meetup.com/meetup_api/key/" urlTemplate = "https://api.meetup.com/%s?sign=true&key=%s" ) client := urlfetch.Client(c) res, err := client.Get(fmt.Sprintf(urlTemplate, id, apiKey)) if err != nil { return nil, fmt.Errorf("get: %v", err) } var g struct { Name string `json:"name"` Link string `json:"link"` City string `json:"city"` Country string `json:"country"` Members int `json:"members"` } dec := json.NewDecoder(res.Body) err = dec.Decode(&g) if err != nil { return nil, fmt.Errorf("decode: %v", err) } return &Group{ Name: g.Name, URL: g.Link, Members: g.Members, City: g.City, Country: g.Country, }, nil }
func getTweetsSync(c RequestContext, bookList []Book) { anaconda.SetConsumerKey(twitterConsumerKey) anaconda.SetConsumerSecret(twitterConsumerSecret) api := anaconda.NewTwitterApi(twitterAccessToken, twitterAccessTokenSecret) api.HttpClient = urlfetch.Client(c) defer api.Close() for i := 0; i < len(bookList); i++ { book := &bookList[i] term := getTwitterKeyword(book.Title) c.Infof("Getting tweets for %s", term) v := url.Values{} v.Add("lang", "en") tweets, err := api.GetSearch(term, nil) if err != nil { c.Errorf("Twitter call failed for %s: %s", term, err) return } book.Tweets = tweets c.Infof("Got %d tweets for %s", len(book.Tweets), term) } sort.Sort(sort.Reverse(BooksByTweets(bookList))) PrintAsJson(c, bookList) }
// query fetches the WeatherValue of a single city by querying the // World Weather Online API. func query(ctx appengine.Context, city string) (WeatherValue, error) { client := urlfetch.Client(ctx) var wv WeatherValue v := url.Values{} v.Set("q", city) v.Add("format", "json") v.Add("key", APIKey) cityURL, err := url.Parse(APIURL + "?" + v.Encode()) if err != nil { return wv, err } // We don't need to handle timeouts as appengine has a default timeout of 5 seconds on client.Get() resp, err := client.Get(cityURL.String()) if err != nil { return wv, err } defer resp.Body.Close() decoder := json.NewDecoder(resp.Body) if err := decoder.Decode(&wv); err != nil { return wv, err } return wv, nil }
func Public(user string, r *http.Request) (gists []Gist, err error) { c := appengine.NewContext(r) var buffer bytes.Buffer buffer.WriteString("https://api.github.com/users/") if len(user) > 0 { buffer.WriteString(user) } else { buffer.WriteString("ninnemana") } buffer.WriteString("/gists") client := urlfetch.Client(c) log.Println(buffer.String()) resp, err := client.Get(buffer.String()) if err != nil { return } defer resp.Body.Close() buffer.Reset() buffer.ReadFrom(resp.Body) gists = make([]Gist, 0) err = json.Unmarshal(buffer.Bytes(), &gists) return }
func collectUrls(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) url := "http://catoverflow.com/api/query?offset=0&limit=1000" client := urlfetch.Client(c) resp, err := client.Get(url) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } //Split the body by new lines to get the url for each image. s := string(body) urls := strings.Fields(s) for _, u := range urls { t := taskqueue.NewPOSTTask("/worker", map[string][]string{"url": {u}}) if _, err := taskqueue.Add(c, t, ""); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } }
// serveTwitterCallback handles callbacks from the Twitter OAuth server. func serveTwitterCallback(c *context) error { token := c.r.FormValue("oauth_token") var ci connectInfo _, err := memcache.Gob.Get(c.c, token, &ci) if err != nil { return err } memcache.Delete(c.c, token) tempCred := &oauth.Credentials{ Token: token, Secret: ci.Secret, } httpClient := urlfetch.Client(c.c) tokenCred, _, err := oauthClient.RequestToken(httpClient, tempCred, c.r.FormValue("oauth_verifier")) if err != nil { return err } if err := c.updateUserInfo(func(u *userInfo) { u.TwitterCred = *tokenCred }); err != nil { return err } http.Redirect(c.w, c.r, ci.Redirect, 302) return nil }
func PostRSVP(data url.Values, r *http.Request) { const layout = "Jan 2, 2006 at 3:04pm (MST)" c := appengine.NewContext(r) client := urlfetch.Client(c) resp, err := client.Post("https://api.meetup.com/2/rsvp?key="+apikey, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) var buf []byte var result interface{} if err != nil { LogError(err) return } buf, err = ioutil.ReadAll(resp.Body) defer resp.Body.Close() json.Unmarshal(buf, &result) log.Printf("RSVP Post Result: %+v\n", result) }
// updateRecipeFromURL is a helper function that attempts to parse the // recipe URL to get the recipe data. If an error occurs, false is // returned and a proper message will have been sent as a // response. This case should be terminal. If a parser isn't available // for the URL, no error is returned, but nothing is changed in the // recipe. func updateRecipeFromURL(c appengine.Context, w http.ResponseWriter, r *http.Request, recipe *Recipe) bool { p, err := parsers.GetParserForURL(recipe.URL) if err != nil { gorca.LogAndUnexpected(c, w, r, err) return false } if p == nil { gorca.Log(c, r, "warn", "no parser found for: %s", recipe.URL) return true } client := urlfetch.Client(c) resp, err := client.Get(recipe.URL) if err != nil { gorca.LogAndUnexpected(c, w, r, err) return false } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { gorca.LogAndUnexpected(c, w, r, err) return false } recipe.Name = p.GetName(body) recipe.Ingredients = p.GetIngredients(body) recipe.Directions = p.GetDirections(body) return true }
func QueryGAE(query string, c appengine.Context) (*Message, error) { // Implement the http.Client with an urlfetch Transport. http := urlfetch.Client(c) query_enc := url.QueryEscape(query) ddgurl := fmt.Sprintf("http://api.duckduckgo.com/?q=%s&format=json&pretty=1", query_enc) resp, err := http.Get(ddgurl) if err != nil { return nil, err } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } var message *Message = &Message{} if err = json.Unmarshal(body, message); err != nil { c.Errorf("%s", body) return nil, err } return message, nil }
func handler(w http.ResponseWriter, r *http.Request) { // "/media/ce7c31_f0e70d3996554b4cfeff3d19aa05739b.jpg_srz_170_150_75_22_0.5_1.20_0.00_jpg_srz" imagePath := r.URL.Path if imagePath == "/favicon.ico" { http.NotFound(w, r) return } c := appengine.NewContext(r) client := urlfetch.Client(c) resp, err := client.Head(FileUrl(imagePath)) if err != nil { HandleError(w, c, err) } else if resp.StatusCode == 200 { // image exists if err = RespondWithHeader(imagePath, c, w, r); err != nil { HandleError(w, c, err) } } else if resp.StatusCode == 404 { // no image, do request to compute engine if err = GetAndRender(imagePath, c, w, r); err != nil { HandleError(w, c, err) } } }
func handler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) client := urlfetch.Client(c) url := fmt.Sprintf("https://www.googleapis.com/plus/v1/people/%s?key=%s", user, key) resp, err := client.Get(url) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } person := Person{} if err := json.Unmarshal(body, &person); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Add("Content-Type", "text/plain") fmt.Fprintln(w, person.DisplayName) }
// disconnect revokes the current user's token and resets their session func disconnect(w http.ResponseWriter, r *http.Request) { // Only disconnect a connected user c := appengine.NewContext(r) client := urlfetch.Client(c) session, err := store.Get(r, "sessionName") if err != nil { c.Infof("error fetching session: %v", err) serveAppError(c, w, &appError{err, "Error fetching session", 500}) return } token := session.Values["accessToken"] c.Infof("Token: %v", token) if token == nil { m := "Current user not connected" serveAppError(c, w, &appError{errors.New(m), "Current user not connected", 401}) return } // Execute HTTP GET request to revoke current token url := "https://accounts.google.com/o/oauth2/revoke?token=" + token.(string) resp, err := client.Get(url) if err != nil { m := "Failed to revoke token for a given user" serveAppError(c, w, &appError{errors.New(m), m, 400}) return } defer resp.Body.Close() // Reset the user's session session.Values["accessToken"] = nil session.Save(r, w) }
// exchange takes an authentication code and exchanges it with the OAuth // endpoint for a Google API bearer token and a Google+ ID func exchange(code string, r *http.Request) (accessToken string, idToken string, err error) { // Exchange the authorization code for a credentials object via a POST request c := appengine.NewContext(r) client := urlfetch.Client(c) values := url.Values{ "Content-Type": {"application/x-www-form-urlencoded"}, "code": {code}, "client_id": {clientID}, "client_secret": {clientSecret}, "redirect_uri": {config.RedirectURL}, "grant_type": {"authorization_code"}, } resp, err := client.PostForm(config.TokenURL, values) if err != nil { return "", "", fmt.Errorf("Exchanging code: %v", err) } defer resp.Body.Close() // Decode the response body into a token object var token Token err = json.NewDecoder(resp.Body).Decode(&token) if err != nil { return "", "", fmt.Errorf("Decoding access token: %v", err) } return token.AccessToken, token.IdToken, nil }
func get_site(uri string, r *http.Request) ([]temp_item, error) { c := appengine.NewContext(r) client := urlfetch.Client(c) resp, err := client.Get(uri) if err != nil { return nil, err } doc, err := goquery.NewDocumentFromResponse(resp) if err != nil { return nil, err } var list_items []temp_item doc.Find("#bodyContent li").Not("#bodyContent #toc li").Each(func(i int, s *goquery.Selection) { listitem := s.Text() c.Infof("ITEM:\n" + listitem + "\n\n") q, err := filter_question(listitem) c.Infof("%v", err) if err == nil { list_items = append(list_items, q) } }) //c.Infof("%+v\n", list_items) return list_items, nil }
func runApiRequest(context appengine.Context, path string) ([]byte, error) { _, authInfos, err := readAuthInfoFromDatastore(context) if err != nil { context.Infof("Failed to load the auth info") return nil, err } requestUrl := baseUrl + path auth := "Bearer " + authInfos[0].AccessToken client := urlfetch.Client(context) request, err := http.NewRequest("GET", requestUrl, nil) request.Header.Add("Authorization", auth) request.Header.Add("Accept", "application/json") context.Infof("About to run request at %s", requestUrl) response, err := client.Do(request) if err != nil { context.Infof("Request failed! %s", err.Error()) return nil, err } body, err := ioutil.ReadAll(response.Body) response.Body.Close() if err != nil { context.Infof("Couldn't read the response body!") return nil, err } return body, nil }
func makeRequest(w http.ResponseWriter, r *http.Request, path string) CGI_Result { c := appengine.NewContext(r) client := urlfetch.Client(c) url_exe := spf(`http://%s%s%s&ts=%s`, dns_cam, path, credentials, urlParamTS()) url_dis := spf(`http://%s%s&ts=%s`, dns_cam, path, urlParamTS()) wpf(w, "<div style='font-size:10px; line-height:11px;'>requesting %v<br></div>\n", url_dis) resp1, err := client.Get(url_exe) loghttp.E(w, r, err, false) bcont, err := ioutil.ReadAll(resp1.Body) defer resp1.Body.Close() loghttp.E(w, r, err, false) cgiRes := CGI_Result{} xmlerr := xml.Unmarshal(bcont, &cgiRes) loghttp.E(w, r, xmlerr, false) if cgiRes.Result != "0" { wpf(w, "<b>RESPONSE shows bad mood:</b><br>\n") psXml := stringspb.IndentedDump(cgiRes) dis := strings.Trim(psXml, "{}") wpf(w, "<pre style='font-size:10px;line-height:11px;'>%v</pre>", dis) } if debug { scont := string(bcont) wpf(w, "<pre style='font-size:10px;line-height:11px;'>%v</pre>", scont) } return cgiRes }
//Transform an orignalUrl to Tinyurl. func getTinyUrl(w http.ResponseWriter, r *http.Request, orignalUrl string, ch chan string) { cxt := appengine.NewContext(r) defer func() { if err := recover(); err != nil { cxt.Errorf("getTinyUrl error but give channel emptry to complete.: %v", err) ch <- EMPTY } }() tingUrl := EMPTY if orignalUrl != EMPTY { rep, _ := url.Parse(orignalUrl) adr := fmt.Sprintf("%s%s", TINY, rep) if req, err := http.NewRequest(API_METHOD, adr, nil); err == nil { httpClient := urlfetch.Client(cxt) res, err := httpClient.Do(req) if res != nil { defer res.Body.Close() } if err == nil { if bytes, err := ioutil.ReadAll(res.Body); err == nil { tingUrl = string(bytes) ch <- tingUrl } else { panic(err) } } else { panic(err) } } else { panic(err) } } else { ch <- EMPTY } }
func res(w http.ResponseWriter, r *http.Request) { // get the keys either from config file options, err := getOptions(w) if err != nil { fmt.Println(err) io.WriteString(w, fmt.Sprintf("ERROR: %v", err)) } // google app engine requires it's own class for making http requests c := appengine.NewContext(r) httpClient := urlfetch.Client(c) // create a new yelp client with the auth keys and the custom http client client := yelp.New(options, httpClient) // make a simple query term := r.URL.Query().Get("term") location := r.URL.Query().Get("location") // call the yelp API results, err := client.DoSimpleSearch(term, location) if err != nil { fmt.Println(err) io.WriteString(w, fmt.Sprintf("ERROR: %v", err)) } // print the results io.WriteString(w, fmt.Sprintf("<div>Found a total of %v results for \"%v\" in \"%v\".</div>", results.Total, term, location)) io.WriteString(w, "<div>-----------------------------</div>") for i := 0; i < len(results.Businesses); i++ { io.WriteString(w, fmt.Sprintf("<div>%v, %v</div>", results.Businesses[i].Name, results.Businesses[i].Rating)) } }
func fetchFacebookStatuses(c appengine.Context) ([]Status, os.Error) { graph_url := "https://graph.facebook.com/" + config.Username + "/statuses" + "?limit=1000&access_token=" + config.AccessToken client := urlfetch.Client(c) response, err := client.Get(graph_url) if err != nil { c.Errorf("Error fetching item from facebook, %s.\nResponse.", err.String()) return nil, err } data, readErr := ioutil.ReadAll(response.Body) response.Body.Close() if readErr != nil { c.Errorf("Error reading bytes from response, %s", readErr) return nil, readErr } var m StatusList jsonErr := json.Unmarshal(data, &m) if jsonErr != nil { c.Errorf("Error unmarshalling json from facebook, %s", jsonErr) return nil, jsonErr } return m.Data, nil }
func verifyMassageWithPaypal(ctx appengine.Context, content string, testIpnField string) error { paypalIpnUrl := PaypalIpn if testIpnField != "" { if testIpnField == "1" { paypalIpnUrl = PaypalIpnSandBox } else { paypalIpnUrl = localIpn } } ctx.Infof("Sending msg to: " + paypalIpnUrl) extraData := []byte("cmd=_notify-validate&") client := urlfetch.Client(ctx) resp, err := client.Post(paypalIpnUrl, FromEncodedContentType, bytes.NewBuffer(append(extraData, content...))) if err != nil { return err } respBody, err := ioutil.ReadAll(resp.Body) resp.Body.Close() ctx.Debugf("Ipn Validation response " + string(respBody)) if err == nil && string(respBody) != "VERIFIED" { return IpnMessageCouldNotBeValidated } return err }
func SubscribeFeed(c mpg.Context, w http.ResponseWriter, r *http.Request) { gn := goon.FromContext(c) f := Feed{Url: r.FormValue("feed")} if err := gn.Get(&f); err != nil { c.Errorf("%v: %v", err, f.Url) serveError(w, err) return } else if f.IsSubscribed() { return } u := url.Values{} u.Add("hub.callback", f.PubSubURL()) u.Add("hub.mode", "subscribe") u.Add("hub.verify", "sync") fu, _ := url.Parse(f.Url) fu.Fragment = "" u.Add("hub.topic", fu.String()) req, err := http.NewRequest("POST", PUBSUBHUBBUB_HUB, strings.NewReader(u.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") cl := urlfetch.Client(c) resp, err := cl.Do(req) if err != nil { c.Errorf("req error: %v", err) } else if resp.StatusCode != 204 { c.Errorf("resp: %v - %v", f.Url, resp.Status) c.Errorf("%s", resp.Body) } else { c.Infof("subscribed: %v", f.Url) } }
func SendInvite(r *http.Request, fname string, lname string, email string) string { // client := &http.Client{} c := appengine.NewContext(r) client := urlfetch.Client(c) baseUrl, token := importConfiguration() req, _ := http.NewRequest("POST", baseUrl, nil) SetSlackToken(req, token) SetFormValues(req, fname, lname, email) resp, err := client.Do(req) if err != nil { fmt.Println("Request error is: ", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("Reading of response error is: ", err) } return string(body) // TODO - add error checking for body of response // success: {"ok":true} // failure: {"ok":false,"error":"already_in_team"} }
func WebHandler(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() code := query.Get("code") if code == "" { http.Error(w, "Cannot get code from facebook.", 505) return } context := appengine.NewContext(r) client := urlfetch.Client(context) fb.SetHttpClient(client) redirectURL := "http://" + r.Host + r.URL.Path accessResp, err := fb.Get("/v2.4/oauth/access_token", fb.Params{ "code": code, "redirect_uri": redirectURL, "client_id": clientID, "client_secret": APPSECRET, }) check(err, context) var accessToken string accessResp.DecodeField("access_token", &accessToken) paths := strings.Split(r.URL.Path, "/") party := paths[len(paths)-1] photoID := UploadPhoto(accessToken, party, context) redirectUrl := "https://facebook.com/photo.php?fbid=" + photoID + "&makeprofile=1&prof" http.Redirect(w, r, redirectUrl, 303) }
func AppEngineVerify(r *http.Request) string { if err := r.ParseForm(); err != nil { return "Anonymous" } token := r.FormValue("assertion") url := "https://browserid.org/verify" bodytype := "application/x-www-form-urlencoded" body := strings.NewReader("assertion=" + token + "&audience=" + r.Host) var response_body []byte c := appengine.NewContext(r) client := urlfetch.Client(c) res, err := client.Post(url, bodytype, body) if err != nil { fmt.Println("err=", err) return "Anonymous" } else { response_body, _ = ioutil.ReadAll(res.Body) res.Body.Close() } var f interface{} json.Unmarshal(response_body, &f) m := f.(map[string]interface{}) return fmt.Sprintf("%s", m["email"]) }
// insertItem inserts a Timeline Item in the user's Timeline. func insertItem(r *http.Request, svc *mirror.Service) string { c := appengine.NewContext(r) c.Infof("Inserting Timeline Item") body := mirror.TimelineItem{ Notification: &mirror.NotificationConfig{Level: "AUDIO_ONLY"}, } if r.FormValue("html") == "on" { body.Html = r.FormValue("message") } else { body.Text = r.FormValue("message") } var media io.Reader = nil mediaLink := r.FormValue("imageUrl") if mediaLink != "" { if strings.HasPrefix(mediaLink, "/") { mediaLink = fullURL(r.Host, mediaLink) } c.Infof("Downloading media from: %s", mediaLink) client := urlfetch.Client(c) if resp, err := client.Get(mediaLink); err != nil { c.Errorf("Unable to retrieve media: %s", err) } else { defer resp.Body.Close() media = resp.Body } } if _, err := svc.Timeline.Insert(&body).Media(media).Do(); err != nil { return fmt.Sprintf("Unable to insert timeline item: %s", err) } return "A timeline item has been inserted." }
/* Does the actual google books API call. */ func lookupISBN(ctx appengine.Context, country string, isbn isbn13.ISBN13) (resp *data.BookMetaData, err error) { var r *http.Response url := fmt.Sprintf(lookupURLTemplate, uint64(isbn), country, apiKey) ctx.Debugf("Calling %s", fmt.Sprintf(lookupURLTemplate, uint64(isbn), country, "<hidden>")) client := urlfetch.Client(ctx) if r, err = client.Get(url); err == nil { if r.StatusCode != http.StatusOK { err = fmt.Errorf("Google API returned %s", r.Status) } else { reply := new(data.LookupReply) decode := json.NewDecoder(r.Body) defer r.Body.Close() ctx.Infof("Completed API call, result %s\n", r.Status) if err = decode.Decode(reply); err == nil { if reply.Count == 1 { resp = &reply.BookInfos[0] } else { ctx.Infof("Google books reported %d matching items: %v", reply.Count, reply) resp = new(data.BookMetaData) resp.Volume.Title = placeHolderText + isbn.String() } resp.Parent = country resp.ISBN = isbn.String() } } } return }