diff --git a/persistence/user_queries.go b/persistence/user_queries.go index d584e54..0f1f30e 100644 --- a/persistence/user_queries.go +++ b/persistence/user_queries.go @@ -146,3 +146,42 @@ func (p Profile) GetUserByID(id scraper.UserID) (scraper.User, error) { } return ret, err } + +/** + * Returns `true` if content download is needed, `false` otherwise + * + * If: + * - the user isn't in the DB at all (first time scraping), OR + * - `is_content_downloaded` is false in the DB, OR + * - the banner / profile image URL has changed from what the DB has + * then it needs to be downloaded. + * + * The `user` object will always have `is_content_downloaded` = false on every scrape. This is + * why the No Worsening Principle is needed. + */ +func (p Profile) CheckUserContentDownloadNeeded(user scraper.User) bool { + row := p.DB.QueryRow(`select is_content_downloaded, profile_image_url, banner_image_url from users where id = ?`, user.ID) + + var is_content_downloaded bool + var profile_image_url string + var banner_image_url string + err := row.Scan(&is_content_downloaded, &profile_image_url, &banner_image_url) + if err != nil { + if err == sql.ErrNoRows { + return true + } else { + panic(err) + } + } + + if !is_content_downloaded { + return true + } + if banner_image_url != user.BannerImageUrl { + return true + } + if profile_image_url != user.ProfileImageUrl { + return true + } + return false +} diff --git a/persistence/user_queries_test.go b/persistence/user_queries_test.go index c687151..ce8a387 100644 --- a/persistence/user_queries_test.go +++ b/persistence/user_queries_test.go @@ -81,3 +81,52 @@ func TestUserExists(t *testing.T) { t.Errorf("It should exist, but it doesn't: %d", user.ID) } } + +/** + * Test scenarios relating to user content downloading + */ +func TestCheckUserContentDownloadNeeded(t *testing.T) { + profile_path := "test_profiles/TestUserQueries" + profile := create_or_load_profile(profile_path) + + user := create_dummy_user() + + // If user is not in database, should be "yes" automatically + if profile.CheckUserContentDownloadNeeded(user) != true { + t.Errorf("Non-saved user should always require content download") + } + + // Save the user, but `is_content_downloaded` is still "false" + user.BannerImageUrl = "banner url1" + user.ProfileImageUrl = "profile url1" + user.IsContentDownloaded = false + err := profile.SaveUser(user) + if err != nil { + panic(err) + } + + // If is_content_downloaded is false, then it needs download + if profile.CheckUserContentDownloadNeeded(user) != true { + t.Errorf("Non-downloaded user should require download") + } + + // Mark `is_content_downloaded` as "true" again + user.IsContentDownloaded = true + err = profile.SaveUser(user) + if err != nil { + panic(err) + } + + // If everything is up to date, no download should be required + if profile.CheckUserContentDownloadNeeded(user) != false { + t.Errorf("Up-to-date user shouldn't need a download") + } + + // Change an URL, but don't save it-- needs to be different from what's in the DB + user.BannerImageUrl = "banner url2" + + // Download needed for new banner image + if profile.CheckUserContentDownloadNeeded(user) != true { + t.Errorf("If banner image changed, user should require another download") + } +}