Skip to content

Commit 1bcbfb1

Browse files
committed
Auto merge of #4649 - rust-lang:exclude-top, r=Turbo87
Add an environment variable to let us exclude crate IDs from the recent downloads list I haven't figured out a great way to add a test for this because I need to create a crate and get a crate ID and then change the app's config, and the test app doesn't easily have this... so I thought I'd throw up this change for discussion and see if anyone had better ideas.
2 parents 0cbb775 + bf912ec commit 1bcbfb1

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Server {
2525
pub blocked_traffic: Vec<(String, Vec<String>)>,
2626
pub max_allowed_page_offset: u32,
2727
pub page_offset_ua_blocklist: Vec<String>,
28+
pub excluded_crate_names: Vec<String>,
2829
pub domain_name: String,
2930
pub allowed_origins: Vec<String>,
3031
pub downloads_persist_interval_ms: usize,
@@ -84,6 +85,11 @@ impl Default for Server {
8485
Some(s) => s.split(',').map(String::from).collect(),
8586
};
8687
let base = Base::from_environment();
88+
let excluded_crate_names = match env_optional::<String>("EXCLUDED_CRATE_NAMES") {
89+
None => vec![],
90+
Some(s) if s.is_empty() => vec![],
91+
Some(s) => s.split(',').map(String::from).collect(),
92+
};
8793
Server {
8894
db: DatabasePools::full_from_environment(&base),
8995
base,
@@ -97,6 +103,7 @@ impl Default for Server {
97103
blocked_traffic: blocked_traffic(),
98104
max_allowed_page_offset: env_optional("WEB_MAX_ALLOWED_PAGE_OFFSET").unwrap_or(200),
99105
page_offset_ua_blocklist,
106+
excluded_crate_names,
100107
domain_name: domain_name(),
101108
allowed_origins,
102109
downloads_persist_interval_ms: dotenv::var("DOWNLOADS_PERSIST_INTERVAL_MS")

src/controllers/krate/metadata.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ use crate::models::krate::ALL_COLUMNS;
2424
/// Handles the `GET /summary` route.
2525
pub fn summary(req: &mut dyn RequestExt) -> EndpointResult {
2626
use crate::schema::crates::dsl::*;
27+
use diesel::dsl::all;
28+
29+
let config = &req.app().config;
2730

2831
let conn = req.db_read_only()?;
2932
let num_crates: i64 = crates.count().get_result(&*conn)?;
@@ -70,15 +73,26 @@ pub fn summary(req: &mut dyn RequestExt) -> EndpointResult {
7073
.select(selection)
7174
.limit(10)
7275
.load(&*conn)?;
73-
let most_downloaded = crates
74-
.left_join(recent_crate_downloads::table)
76+
77+
let mut most_downloaded_query = crates.left_join(recent_crate_downloads::table).into_boxed();
78+
if !config.excluded_crate_names.is_empty() {
79+
most_downloaded_query =
80+
most_downloaded_query.filter(name.ne(all(&config.excluded_crate_names)));
81+
}
82+
let most_downloaded = most_downloaded_query
7583
.then_order_by(downloads.desc())
7684
.select(selection)
7785
.limit(10)
7886
.load(&*conn)?;
7987

80-
let most_recently_downloaded = crates
88+
let mut most_recently_downloaded_query = crates
8189
.inner_join(recent_crate_downloads::table)
90+
.into_boxed();
91+
if !config.excluded_crate_names.is_empty() {
92+
most_recently_downloaded_query =
93+
most_recently_downloaded_query.filter(name.ne(all(&config.excluded_crate_names)));
94+
}
95+
let most_recently_downloaded = most_recently_downloaded_query
8296
.then_order_by(recent_crate_downloads::downloads.desc())
8397
.select(selection)
8498
.limit(10)

src/tests/krate/summary.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,46 @@ fn summary_new_crates() {
107107

108108
assert_eq!(json.new_crates.len(), 5);
109109
}
110+
111+
#[test]
112+
fn excluded_crate_id() {
113+
let (app, anon, user) = TestApp::init()
114+
.with_config(|config| {
115+
config.excluded_crate_names = vec![
116+
"most_recent_downloads".into(),
117+
// make sure no error occurs with a crate name that doesn't exist and that the name
118+
// matches are exact, not substrings
119+
"downloads".into(),
120+
];
121+
})
122+
.with_user();
123+
let user = user.as_model();
124+
app.db(|conn| {
125+
CrateBuilder::new("some_downloads", user.id)
126+
.version(VersionBuilder::new("0.1.0"))
127+
.description("description")
128+
.keyword("popular")
129+
.category("cat1")
130+
.downloads(20)
131+
.recent_downloads(10)
132+
.expect_build(conn);
133+
134+
CrateBuilder::new("most_recent_downloads", user.id)
135+
.version(VersionBuilder::new("0.2.0"))
136+
.keyword("popular")
137+
.category("cat1")
138+
.downloads(5000)
139+
.recent_downloads(50)
140+
.expect_build(conn);
141+
});
142+
143+
let json: SummaryResponse = anon.get("/api/v1/summary").good();
144+
145+
assert_eq!(json.most_downloaded.len(), 1);
146+
assert_eq!(json.most_downloaded[0].name, "some_downloads");
147+
assert_eq!(json.most_downloaded[0].downloads, 20);
148+
149+
assert_eq!(json.most_recently_downloaded.len(), 1);
150+
assert_eq!(json.most_recently_downloaded[0].name, "some_downloads");
151+
assert_eq!(json.most_recently_downloaded[0].recent_downloads, Some(10));
152+
}

src/tests/util/test_app.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ fn simple_config() -> config::Server {
300300
blocked_traffic: Default::default(),
301301
max_allowed_page_offset: 200,
302302
page_offset_ua_blocklist: vec![],
303+
excluded_crate_names: vec![],
303304
domain_name: "crates.io".into(),
304305
allowed_origins: Vec::new(),
305306
downloads_persist_interval_ms: 1000,

0 commit comments

Comments
 (0)