Skip to content

Commit 059b87b

Browse files
author
Maurício Linhares
committed
Hides crates on index calls unless they have at least one available version
This makes the index call only show crates that have at least one available version. Crates that have all versions yanked will not show up anymore. Fixes #958
1 parent 97e1474 commit 059b87b

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

src/krate.rs

+24
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,30 @@ pub fn index(req: &mut Request) -> CargoResult<Response> {
696696
));
697697
}
698698

699+
if vec![params.get("user_id"), params.get("team_id")]
700+
.iter()
701+
.any(|s| s.is_some())
702+
{
703+
let not_yanked_versions = sql::<Bool>(
704+
"crates.id = ANY (SELECT vs.crate_id FROM versions vs WHERE vs.crate_id = crates.id AND vs.yanked IS FALSE)",
705+
);
706+
707+
query = query.filter(not_yanked_versions.clone())
708+
709+
/*
710+
query = query.filter(
711+
crates::id.eq_any(
712+
versions::table
713+
.select(versions::crate_id)
714+
.left_join(
715+
versions.on(
716+
crates::id.eq(versions::crate_id)
717+
.and(versions::yanked.eq(false))))
718+
.filter(versions::id.is_null())
719+
));
720+
*/
721+
}
722+
699723
// The database query returns a tuple within a tuple , with the root
700724
// tuple containing 3 items.
701725
let data = query

src/tests/krate.rs

+113
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
extern crate diesel;
2+
extern crate conduit;
23

34
use std::collections::HashMap;
45
use std::io::prelude::*;
@@ -1853,6 +1854,7 @@ fn yanked_versions_not_included_in_reverse_dependencies() {
18531854
assert_eq!(deps.dependencies[0].crate_id, "c1");
18541855

18551856
// TODO: have this test call `version.yank()` once the yank method is converted to diesel
1857+
18561858
diesel::update(versions::table.filter(versions::num.eq("2.0.0")))
18571859
.set(versions::yanked.eq(true))
18581860
.execute(&*app.diesel_database.get().unwrap())
@@ -2146,6 +2148,117 @@ fn test_default_sort_recent() {
21462148
assert_eq!(json.crates[1].downloads, 20);
21472149
}
21482150

2151+
/* Given two crates, one with all versions yanked and another
2152+
with a good version only the one that doesn't have all versions
2153+
yanked is returned if a user_id or team_id is provided.
2154+
*/
2155+
#[test]
2156+
fn test_hides_yanked_crate() {
2157+
let (_b, app, middle) = ::app();
2158+
2159+
let (user, team) = {
2160+
let conn = app.diesel_database.get().unwrap();
2161+
let user = ::new_user("Oskar").create_or_update(&conn).unwrap();
2162+
let team = ::new_team("github:test_org:team_sloth")
2163+
.create_or_update(&conn)
2164+
.unwrap();
2165+
2166+
let green_ball = ::CrateBuilder::new("green_ball", user.id)
2167+
.description("For fetching")
2168+
.downloads(0)
2169+
.recent_downloads(0)
2170+
.expect_build(&conn);
2171+
2172+
::add_team_to_crate(&team, &green_ball, &user, &conn).unwrap();
2173+
2174+
let yanked_crate = ::CrateBuilder::new("fully_yanked", user.id)
2175+
.description("Not here anymore")
2176+
.expect_build(&conn);
2177+
2178+
::add_team_to_crate(&team, &yanked_crate, &user, &conn).unwrap();
2179+
2180+
diesel::update(versions::table.filter(
2181+
versions::crate_id.eq(yanked_crate.id),
2182+
)).set(versions::yanked.eq(true))
2183+
.execute(&*conn)
2184+
.unwrap();
2185+
2186+
(user, team)
2187+
};
2188+
2189+
{
2190+
let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates");
2191+
let mut response = ok_resp!(middle.call(req.with_query(
2192+
format!("sort=recent-downloads&user_id={}", user.id).as_str(),
2193+
)));
2194+
assert_crate_yanked(&mut response);
2195+
}
2196+
2197+
{
2198+
let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates");
2199+
let mut response = ok_resp!(middle.call(req.with_query(
2200+
format!("sort=recent-downloads&team_id={}", team.id).as_str(),
2201+
)));
2202+
assert_crate_yanked(&mut response);
2203+
}
2204+
}
2205+
2206+
fn assert_crate_yanked(response: &mut conduit::Response) {
2207+
let json: CrateList = ::json(response);
2208+
2209+
assert_eq!(json.meta.total, 1);
2210+
2211+
assert_eq!(json.crates[0].name, "green_ball");
2212+
assert_eq!(json.crates[0].recent_downloads, Some(0));
2213+
assert_eq!(json.crates[0].downloads, 0);
2214+
}
2215+
2216+
/* Given two crates, one with all versions yanked and another
2217+
with a good version, both crates are returned if there is
2218+
no user_id or team_id provided.
2219+
*/
2220+
#[test]
2221+
fn test_shows_yanked_crate_without_user_or_team() {
2222+
let (_b, app, middle) = ::app();
2223+
2224+
{
2225+
let conn = app.diesel_database.get().unwrap();
2226+
let user = ::new_user("Oskar").create_or_update(&conn).unwrap();
2227+
2228+
::CrateBuilder::new("green_ball", user.id)
2229+
.description("For fetching")
2230+
.downloads(0)
2231+
.recent_downloads(0)
2232+
.expect_build(&conn);
2233+
2234+
let yanked_crate = ::CrateBuilder::new("fully_yanked", user.id)
2235+
.description("Not here anymore")
2236+
.expect_build(&conn);
2237+
2238+
diesel::update(versions::table.filter(
2239+
versions::crate_id.eq(yanked_crate.id),
2240+
)).set(versions::yanked.eq(true))
2241+
.execute(&*conn)
2242+
.unwrap();
2243+
}
2244+
2245+
2246+
let mut req = ::req(app.clone(), Method::Get, "/api/v1/crates");
2247+
let mut response = ok_resp!(middle.call(req.with_query("sort=recent-downloads")));
2248+
2249+
let json: CrateList = ::json(&mut response);
2250+
2251+
assert_eq!(json.meta.total, 2);
2252+
2253+
assert_eq!(json.crates[0].name, "green_ball");
2254+
assert_eq!(json.crates[0].recent_downloads, Some(0));
2255+
assert_eq!(json.crates[0].downloads, 0);
2256+
2257+
assert_eq!(json.crates[1].name, "fully_yanked");
2258+
assert_eq!(json.crates[1].recent_downloads, Some(0));
2259+
assert_eq!(json.crates[1].downloads, 0);
2260+
}
2261+
21492262
#[test]
21502263
fn block_blacklisted_documentation_url() {
21512264
let (_b, app, middle) = ::app();

0 commit comments

Comments
 (0)