func importSubscription(pfc *PFContext, ch chan<- *rss.Outline, userID storage.UserID, folderRef storage.FolderRef, outline *rss.Outline) { c := pfc.C subscriptionURL := outline.FeedURL if subscribed, err := storage.IsSubscriptionDuplicate(pfc.C, userID, subscriptionURL); err != nil { c.Errorf("Cannot determine if '%s' is duplicate: %s", subscriptionURL, err) goto done } else if subscribed { c.Infof("Already subscribed to %s", subscriptionURL) goto done // Already subscribed } if feed, err := storage.FeedByURL(pfc.C, subscriptionURL); err != nil { c.Errorf("Error locating feed %s: %s", subscriptionURL, err.Error()) goto done } else if feed == nil { // Feed not available locally - fetch it client := createHttpClient(pfc.C) if response, err := client.Get(subscriptionURL); err != nil { c.Errorf("Error downloading feed %s: %s", subscriptionURL, err) goto done } else { defer response.Body.Close() if parsedFeed, err := rss.UnmarshalStream(subscriptionURL, response.Body); err != nil { c.Errorf("Error reading RSS content (%s): %s", subscriptionURL, err) goto done } else { favIconURL := "" if parsedFeed.WWWURL != "" { if url, err := locateFavIconURL(pfc.C, parsedFeed.WWWURL); err != nil { // Not critical pfc.C.Warningf("FavIcon retrieval error: %s", err) } else if url != "" { favIconURL = url } } if err := storage.UpdateFeed(pfc.C, parsedFeed, favIconURL, time.Now()); err != nil { c.Errorf("Error updating feed: %s", err) goto done } } } } if subscriptionRef, err := storage.Subscribe(pfc.C, folderRef, subscriptionURL, outline.Title); err != nil { c.Errorf("Error subscribing to feed %s: %s", subscriptionURL, err) goto done } else { if _, err := storage.UpdateSubscription(pfc.C, subscriptionURL, subscriptionRef); err != nil { c.Errorf("Error updating subscription %s: %s", subscriptionURL, err) goto done } } done: ch <- outline }
func subscribe(pfc *PFContext) (interface{}, error) { c := pfc.C r := pfc.R subscriptionURL := r.PostFormValue("url") folderId := r.PostFormValue("folder") if subscriptionURL == "" { return nil, NewReadableError(_l("Missing URL"), nil) } else if _, err := url.ParseRequestURI(subscriptionURL); err != nil { return nil, NewReadableError(_l("URL is not valid"), &err) } folderRef := storage.FolderRef{ UserID: pfc.UserID, FolderID: folderId, } if folderId != "" { if exists, err := storage.FolderExists(pfc.C, folderRef); err != nil { return nil, err } else if !exists { return nil, NewReadableError(_l("Folder not found"), nil) } } feedTitle := _l("New Subscription") if exists, err := storage.IsFeedAvailable(pfc.C, subscriptionURL); err != nil { return nil, err } else if !exists { // Not a known feed URL // Match it against a list of known WWW links if feedURL, err := storage.WebToFeedURL(pfc.C, subscriptionURL, &feedTitle); err != nil { return nil, err } else if feedURL != "" { subscriptionURL = feedURL } else { // Still nothing // Add/remove 'www' to/from URL and try again var modifiedURL string if re := regexp.MustCompile(`://www\.`); re.MatchString(subscriptionURL) { modifiedURL = re.ReplaceAllString(subscriptionURL, "://") } else { re = regexp.MustCompile(`://`) modifiedURL = re.ReplaceAllString(subscriptionURL, "://www.") } if feedURL, err := storage.WebToFeedURL(pfc.C, modifiedURL, &feedTitle); err != nil { return nil, err } else if feedURL != "" { subscriptionURL = feedURL } } } else if feed, err := storage.FeedByURL(pfc.C, subscriptionURL); err == nil { if feed.Title != "" { feedTitle = feed.Title } } if subscribed, err := storage.IsSubscriptionDuplicate(pfc.C, pfc.UserID, subscriptionURL); err != nil { return nil, err } else if subscribed { return nil, NewReadableError(_l("You are already subscribed to %s", feedTitle), nil) } // At this point, the URL may have been re-written, so we check again if exists, err := storage.IsFeedAvailable(pfc.C, subscriptionURL); err != nil { return nil, err } else if !exists { // Don't have the feed locally - fetch it client := createHttpClient(c) if response, err := client.Get(subscriptionURL); err != nil { return nil, NewReadableError(_l("An error occurred while downloading the feed"), &err) } else { defer response.Body.Close() var body string if bytes, err := ioutil.ReadAll(response.Body); err != nil { return nil, NewReadableError(_l("An error occurred while reading the feed"), &err) } else { body = string(bytes) } reader := strings.NewReader(body) if feed, err := rss.UnmarshalStream(subscriptionURL, reader); err != nil { c.Warningf("Error parsing RSS (URL %s): %s", subscriptionURL, err) // Parse failed. Assume it's an HTML document and // try to pull out an RSS <link /> if linkURL, err := rss.ExtractRSSLink(c, subscriptionURL, body); linkURL == "" || err != nil { return nil, NewReadableError(_l("RSS content not found (and no RSS links to follow)"), &err) } else { // Validate the RSS file if response, err := client.Get(linkURL); err != nil { return nil, NewReadableError(_l("An error occurred while downloading the feed"), &err) } else { defer response.Body.Close() if feed, err := rss.UnmarshalStream(linkURL, response.Body); err != nil { return nil, NewReadableError(_l("RSS content not found"), &err) } else { feedTitle = feed.Title } subscriptionURL = linkURL } } } else { feedTitle = feed.Title } } } else if feed, err := storage.FeedByURL(pfc.C, subscriptionURL); err == nil { if feed.Title != "" { feedTitle = feed.Title } } // Create subscription entry if _, err := storage.Subscribe(pfc.C, folderRef, subscriptionURL, feedTitle); err != nil { return nil, NewReadableError(_l("Cannot subscribe"), &err) } params := taskParams{ "url": subscriptionURL, "folderID": folderId, } if err := startTask(pfc, "subscribe", params, subscriptionQueue); err != nil { return nil, NewReadableError(_l("Cannot subscribe - too busy"), &err) } return storage.NewUserSubscriptions(c, pfc.UserID) }