Example #1
0
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
}
Example #2
0
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)
}