Skip to content

Commit f833e0f

Browse files
committed
Add most starred crates
1 parent 04ff2f8 commit f833e0f

File tree

5 files changed

+147
-46
lines changed

5 files changed

+147
-46
lines changed

src/web/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ impl CratesfyiHandler {
5959
let mut router = Router::new();
6060
router.get("/", releases::home_page);
6161
router.get("/releases", releases::releases_handler);
62-
router.get("/releases/:page", releases::releases_handler);
62+
router.get("/releases/recent/:page", releases::releases_handler);
63+
router.get("/releases/stars", releases::stars_handler);
64+
router.get("/releases/stars/:page", releases::stars_handler);
6365
router.get("/rustdoc/:crate", rustdoc::rustdoc_redirector_handler);
6466
router.get("/rustdoc/:crate/", rustdoc::rustdoc_redirector_handler);
6567
router.get("/rustdoc/:crate/:version", rustdoc::rustdoc_redirector_handler);

src/web/releases.rs

Lines changed: 112 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ struct Release {
2626
target_name: Option<String>,
2727
rustdoc_status: bool,
2828
release_time: time::Timespec,
29+
stars: i32,
30+
}
31+
32+
33+
impl Default for Release {
34+
fn default() -> Release {
35+
Release {
36+
name: String::new(),
37+
version: String::new(),
38+
description: None,
39+
target_name: None,
40+
rustdoc_status: false,
41+
release_time: time::get_time(),
42+
stars: 0,
43+
}
44+
}
2945
}
3046

3147

@@ -39,36 +55,59 @@ impl ToJson for Release {
3955
m.insert("rustdoc_status".to_string(), self.rustdoc_status.to_json());
4056
m.insert("release_time".to_string(),
4157
duration_to_str(self.release_time).to_json());
58+
m.insert("stars".to_string(), self.stars.to_json());
4259
m.to_json()
4360
}
4461
}
4562

4663

47-
fn get_releases(conn: &Connection, page: i64, limit: i64) -> Vec<Release> {
48-
let mut packages = Vec::new();
64+
enum Order {
65+
ReleaseTime, // this is default order
66+
GithubStars,
67+
}
68+
69+
70+
fn get_releases(conn: &Connection, page: i64, limit: i64, order: Order) -> Vec<Release> {
4971

5072
let offset = (page - 1) * limit;
5173

52-
for row in &conn.query("SELECT crates.name, \
53-
releases.version, \
54-
releases.description, \
55-
releases.target_name, \
56-
releases.release_time, \
57-
releases.rustdoc_status \
58-
FROM crates \
59-
INNER JOIN releases ON crates.id = releases.crate_id \
60-
ORDER BY releases.release_time DESC \
61-
LIMIT $1 OFFSET $2",
62-
&[&limit, &offset])
63-
.unwrap() {
74+
// TODO: This function changed so much during development and current version have code
75+
// repeats for queries. There is definitely room for improvements.
76+
let query = match order {
77+
Order::ReleaseTime => "SELECT crates.name, \
78+
releases.version, \
79+
releases.description, \
80+
releases.target_name, \
81+
releases.release_time, \
82+
releases.rustdoc_status, \
83+
crates.github_stars \
84+
FROM crates \
85+
INNER JOIN releases ON crates.id = releases.crate_id \
86+
ORDER BY releases.release_time DESC \
87+
LIMIT $1 OFFSET $2",
88+
Order::GithubStars => "SELECT crates.name, \
89+
releases.version, \
90+
releases.description, \
91+
releases.target_name, \
92+
releases.release_time, \
93+
releases.rustdoc_status, \
94+
crates.github_stars \
95+
FROM crates \
96+
INNER JOIN releases ON releases.id = crates.latest_version_id \
97+
ORDER BY crates.github_stars DESC \
98+
LIMIT $1 OFFSET $2",
99+
};
64100

101+
let mut packages = Vec::new();
102+
for row in &conn.query(&query, &[&limit, &offset]).unwrap() {
65103
let package = Release {
66104
name: row.get(0),
67105
version: row.get(1),
68106
description: row.get(2),
69107
target_name: row.get(3),
70108
release_time: row.get(4),
71109
rustdoc_status: row.get(5),
110+
stars: row.get(6),
72111
};
73112

74113
packages.push(package);
@@ -110,6 +149,7 @@ fn get_search_results(conn: &Connection,
110149
target_name: row.get(3),
111150
release_time: row.get(4),
112151
rustdoc_status: row.get(5),
152+
..Release::default()
113153
};
114154

115155
packages.push(package);
@@ -131,7 +171,7 @@ fn get_search_results(conn: &Connection,
131171

132172
pub fn home_page(req: &mut Request) -> IronResult<Response> {
133173
let conn = req.extensions.get::<Pool>().unwrap();
134-
let packages = get_releases(conn, 1, RELEASES_IN_HOME);
174+
let packages = get_releases(conn, 1, RELEASES_IN_HOME, Order::ReleaseTime);
135175
Page::new(packages)
136176
.set_true("show_search_form")
137177
.set_true("hide_package_navigation")
@@ -140,7 +180,6 @@ pub fn home_page(req: &mut Request) -> IronResult<Response> {
140180

141181

142182
pub fn releases_handler(req: &mut Request) -> IronResult<Response> {
143-
144183
// page number of releases
145184
let page_number: i64 = req.extensions
146185
.get::<Router>()
@@ -151,31 +190,68 @@ pub fn releases_handler(req: &mut Request) -> IronResult<Response> {
151190
.unwrap_or(1);
152191

153192
let conn = req.extensions.get::<Pool>().unwrap();
154-
let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES);
155-
let page = {
156-
let page = Page::new(packages)
157-
.title("Recent Releases")
158-
.set_int("next_page", page_number + 1);
159-
160-
// Set previous page if we are not in first page
161-
// TODO: Currently, there is no way to know we are on the last page.
162-
// TBH I kinda don't care. COUNT(*) is expensive, and there is more than
163-
// 25k release anyway, I don't think people will check last page. I can cache
164-
// result and use this value for approximation. But since I don't know how to
165-
// do it yet, I will just skip page checking. I can also assume if Package count
166-
// is less than RELEASES_IN_RELEASES, we are on last page.
167-
if page_number == 1 {
168-
page
169-
} else {
170-
page.set_int("previous_page", page_number - 1)
171-
}
172-
};
193+
let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::ReleaseTime);
173194

195+
if packages.is_empty() {
196+
return Err(IronError::new(NoCrate, status::NotFound));
197+
}
174198

175-
page.set_int("next_page", page_number + 1).to_resp("releases")
199+
// Show next and previous page buttons
200+
// This is a temporary solution to avoid expensive COUNT(*)
201+
let (show_next_page, show_previous_page) = (packages.len() == RELEASES_IN_RELEASES as usize,
202+
page_number != 1);
203+
204+
Page::new(packages)
205+
.title("Releases")
206+
.set("description", "Recently uploaded crates")
207+
.set("release_type", "recent")
208+
.set_true("show_releases_navigation")
209+
.set_true("releases_navigation_recent_tab")
210+
.set_bool("show_next_page_button", show_next_page)
211+
.set_int("next_page", page_number + 1)
212+
.set_bool("show_previous_page_button", show_previous_page)
213+
.set_int("previous_page", page_number - 1)
214+
.to_resp("releases")
176215
}
177216

178217

218+
// TODO: This function is almost identical to previous one
219+
pub fn stars_handler(req: &mut Request) -> IronResult<Response> {
220+
// page number of releases
221+
let page_number: i64 = req.extensions
222+
.get::<Router>()
223+
.unwrap()
224+
.find("page")
225+
.unwrap_or("1")
226+
.parse()
227+
.unwrap_or(1);
228+
229+
let conn = req.extensions.get::<Pool>().unwrap();
230+
let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::GithubStars);
231+
232+
if packages.is_empty() {
233+
return Err(IronError::new(NoCrate, status::NotFound));
234+
}
235+
236+
// Show next and previous page buttons
237+
// This is a temporary solution to avoid expensive COUNT(*)
238+
let (show_next_page, show_previous_page) = (packages.len() == RELEASES_IN_RELEASES as usize,
239+
page_number != 1);
240+
241+
Page::new(packages)
242+
.title("Releases")
243+
.set("description", "Most starred crates")
244+
.set("release_type", "stars")
245+
.set_true("show_releases_navigation")
246+
.set_true("releases_navigation_stars_tab")
247+
.set_true("show_stars")
248+
.set_bool("show_next_page_button", show_next_page)
249+
.set_int("next_page", page_number + 1)
250+
.set_bool("show_previous_page_button", show_previous_page)
251+
.set_int("previous_page", page_number - 1)
252+
.to_resp("releases")
253+
}
254+
179255

180256
pub fn search_handler(req: &mut Request) -> IronResult<Response> {
181257
use params::{Params, Value};

templates/navigation.hbs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@
3434
</div>
3535
{{/with}}
3636
{{/if}}
37+
{{#if ../varsb.show_releases_navigation}}
38+
<div class="pure-menu pure-menu-horizontal">
39+
<ul class="pure-menu-list">
40+
<li class="pure-menu-item"><a href="/releases" class="pure-menu-link{{#if ../../varsb.releases_navigation_recent_tab}} pure-menu-active{{/if}}"><i class="fa fa-fw fa-leaf"></i> Recent</a></li>
41+
<li class="pure-menu-item"><a href="/releases/stars" class="pure-menu-link{{#if ../../varsb.releases_navigation_stars_tab}} pure-menu-active{{/if}}"><i class="fa fa-fw fa-star"></i> Stars</a></li>
42+
<li class="pure-menu-item"><a href="/releases/authors" class="pure-menu-link{{#if ../../varsb.releases_navigation_authors_tab}} pure-menu-active{{/if}}"><i class="fa fa-fw fa-user"></i> Authors</a></li>
43+
</ul>
44+
</div>
45+
{{/if}}
3746
</div>
3847
</div>
3948
{{/with}}

templates/releases.hbs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,25 @@
2929
<div class="pure-g">
3030
<div class="pure-u-1 pure-u-sm-5-24 pure-u-md-4-24 name">{{name}}-{{version}}</div>
3131
<div class="pure-u-1 pure-u-sm-15-24 pure-u-md-17-24 description">{{description}}</div>
32+
{{#unless ../../varsb.show_stars}}
3233
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date">{{release_time}}</div>
34+
{{else}}
35+
<div class="pure-u-1 pure-u-sm-4-24 pure-u-md-3-24 date">{{stars}} <i class="fa fa-star-o"></i></div>
36+
{{/unless}}
3337
</div>
3438
</a>
3539
</li>
3640
{{/each}}
3741
</ul>
38-
<!-- TODO: Add next and previous page buttons -->
39-
{{#if varsi.previous_page}}
40-
<a class="pure-button pure-button-normal" href="/releases/{{varsi.previous_page}}">Newest Releases</a>
41-
{{/if}}
4242
{{#unless varsb.show_search_form}}
43-
{{#if varsi.next_page}}
44-
<a class="pure-button pure-button-normal" href="/releases/{{varsi.next_page}}">Oldest Releases</a>
45-
{{/if}}
43+
<div class="pagination">
44+
{{#if varsb.show_previous_page_button}}
45+
<a class="pure-button pure-button-normal" href="/releases/{{varss.release_type}}/{{varsi.previous_page}}"><i class="fa fa-arrow-left"></i> Previous Page</a>
46+
{{/if}}
47+
{{#if varsb.show_next_page_button}}
48+
<a class="pure-button pure-button-normal" href="/releases/{{varss.release_type}}/{{varsi.next_page}}">Next Page <i class="fa fa-arrow-right"></i></a>
49+
{{/if}}
50+
</div>
4651
{{/unless}}
4752
</div>
4853
</div>

templates/style.scss

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ div.recent-releases-container {
155155
background-color: $color-background-code;
156156
}
157157

158+
li:last-child .release {
159+
border-bottom: none;
160+
}
161+
158162
.name {
159163
color: $color-url;
160164
font-weight: 500;
@@ -185,8 +189,13 @@ div.recent-releases-container {
185189
}
186190
}
187191

188-
.pure-button {
189-
margin: .4em 1em;
192+
div.pagination {
193+
text-align: center;
194+
margin: 1em;
195+
196+
.pure-button {
197+
margin: 0;
198+
}
190199
}
191200
}
192201

0 commit comments

Comments
 (0)