Skip to content

Commit 3bf715c

Browse files
committed
Auto merge of #1642 - bryanburgers:exclude-yanked-crates-on-user-team-pages, r=sgrif
Exclude yanked crates on user/team pages Add a URL parameter to the `/api/v1/crates` endpoint that specifies whether or not the endpoint should return crates that have been fully yanked - i.e., where every version has been yanked. If not specified, this defaults to `true` because we have typically always returned all matching crates, whether or not their versions have been yanked. This makes it possible to display only non-yanked crates at various places in the UI without changing Rust code. Use this from the user and team pages to exclude yanked crates from them. Closes #958
2 parents 002e63d + 4be4d4d commit 3bf715c

File tree

4 files changed

+59
-0
lines changed

4 files changed

+59
-0
lines changed

app/routes/team.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default Route.extend({
1616
return this.store.queryRecord('team', { team_id }).then(
1717
team => {
1818
params.team_id = team.get('id');
19+
params.include_yanked = 'n';
1920
return RSVP.hash({
2021
crates: this.store.query('crate', params),
2122
team,

app/routes/user.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default Route.extend({
1515
return this.store.queryRecord('user', { user_id }).then(
1616
user => {
1717
params.user_id = user.get('id');
18+
params.include_yanked = 'n';
1819
return RSVP.hash({
1920
crates: this.store.query('crate', params),
2021
user,

src/controllers/krate/search.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Endpoint for searching and discovery functionality
22
3+
use diesel::dsl::*;
34
use diesel::sql_types::{NotNull, Nullable};
45
use diesel_full_text_search::*;
56

@@ -44,6 +45,10 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
4445
.map(|s| &**s)
4546
.unwrap_or("recent-downloads");
4647
let mut has_filter = false;
48+
let include_yanked = params
49+
.get("include_yanked")
50+
.map(|s| s == "yes")
51+
.unwrap_or(true);
4752

4853
let selection = (
4954
ALL_COLUMNS,
@@ -154,6 +159,15 @@ pub fn search(req: &mut dyn Request) -> CargoResult<Response> {
154159
);
155160
}
156161

162+
if !include_yanked {
163+
has_filter = true;
164+
query = query.filter(exists(
165+
versions::table
166+
.filter(versions::crate_id.eq(crates::id))
167+
.filter(versions::yanked.eq(false)),
168+
));
169+
}
170+
157171
if sort == "downloads" {
158172
query = query.then_order_by(crates::downloads.desc())
159173
} else if sort == "recent-downloads" {

src/tests/krate.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,49 @@ fn loose_search_order() {
454454
}
455455
}
456456

457+
#[test]
458+
fn index_include_yanked() {
459+
let (app, anon, user) = TestApp::init().with_user();
460+
let user = user.as_model();
461+
462+
app.db(|conn| {
463+
CrateBuilder::new("unyanked", user.id)
464+
.version(VersionBuilder::new("1.0.0"))
465+
.version(VersionBuilder::new("2.0.0"))
466+
.expect_build(conn);
467+
468+
CrateBuilder::new("newest_yanked", user.id)
469+
.version(VersionBuilder::new("1.0.0"))
470+
.version(VersionBuilder::new("2.0.0").yanked(true))
471+
.expect_build(conn);
472+
473+
CrateBuilder::new("oldest_yanked", user.id)
474+
.version(VersionBuilder::new("1.0.0").yanked(true))
475+
.version(VersionBuilder::new("2.0.0"))
476+
.expect_build(conn);
477+
478+
CrateBuilder::new("all_yanked", user.id)
479+
.version(VersionBuilder::new("1.0.0").yanked(true))
480+
.version(VersionBuilder::new("2.0.0").yanked(true))
481+
.expect_build(conn);
482+
});
483+
484+
// Include fully yanked (all versions were yanked) crates
485+
let json = anon.search("include_yanked=yes&sort=alphabetical");
486+
assert_eq!(json.meta.total, 4);
487+
assert_eq!(json.crates[0].name, "all_yanked");
488+
assert_eq!(json.crates[1].name, "newest_yanked");
489+
assert_eq!(json.crates[2].name, "oldest_yanked");
490+
assert_eq!(json.crates[3].name, "unyanked");
491+
492+
// Do not include fully yanked (all versions were yanked) crates
493+
let json = anon.search("include_yanked=no&sort=alphabetical");
494+
assert_eq!(json.meta.total, 3);
495+
assert_eq!(json.crates[0].name, "newest_yanked");
496+
assert_eq!(json.crates[1].name, "oldest_yanked");
497+
assert_eq!(json.crates[2].name, "unyanked");
498+
}
499+
457500
#[test]
458501
fn show() {
459502
let (app, anon, user) = TestApp::init().with_user();

0 commit comments

Comments
 (0)