Skip to content

Commit 09b3e7b

Browse files
authored
Merge pull request #416 from wlonk/user-group-crates-list
Show user details.
2 parents cb4e083 + 6f7fc78 commit 09b3e7b

File tree

9 files changed

+147
-4
lines changed

9 files changed

+147
-4
lines changed

app/controllers/user.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Ember from 'ember';
2+
import PaginationMixin from '../mixins/pagination';
3+
4+
const { computed } = Ember;
5+
6+
// TODO: reduce duplication with controllers/crates
7+
8+
export default Ember.Controller.extend(PaginationMixin, {
9+
queryParams: ['page', 'per_page', 'sort'],
10+
page: '1',
11+
per_page: 10,
12+
sort: 'alpha',
13+
14+
totalItems: computed.readOnly('model.crates.meta.total'),
15+
16+
currentSortBy: computed('sort', function() {
17+
return (this.get('sort') === 'downloads') ? 'Downloads' : 'Alphabetical';
18+
}),
19+
});

app/router.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Router.map(function() {
2727
this.route('crates');
2828
this.route('following');
2929
});
30+
this.route('user', { path: '/users/:user_id' });
3031
this.route('install');
3132
this.route('search');
3233
this.route('dashboard');

app/routes/user.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Ember from 'ember';
2+
3+
export default Ember.Route.extend({
4+
queryParams: {
5+
page: { refreshModel: true },
6+
sort: { refreshModel: true },
7+
},
8+
data: {},
9+
10+
setupController(controller, model) {
11+
this._super(controller, model);
12+
13+
controller.set('fetchingFeed', true);
14+
controller.set('crates', this.get('data.crates'));
15+
},
16+
17+
model(params) {
18+
const { user_id } = params;
19+
return this.store.find('user', user_id).then(
20+
(user) => {
21+
params.user_id = user.get('id');
22+
return Ember.RSVP.hash({
23+
crates: this.store.query('crate', params),
24+
user
25+
});
26+
},
27+
(e) => {
28+
if (e.errors.any(e => e.detail === 'Not Found')) {
29+
this
30+
.controllerFor('application')
31+
.set('nextFlashError', `User '${params.user_id}' does not exist`);
32+
return this.replaceWith('index');
33+
}
34+
}
35+
);
36+
},
37+
});

app/styles/crate.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
@include display-flex;
1212
@include align-items(center);
1313
}
14-
h1 { padding-left: 10px; }
14+
h1 {
15+
padding-left: 10px;
16+
padding-right: 10px;
17+
}
1518
h2 { color: $main-color-light; padding-left: 10px; }
1619
.right {
1720
@include flex(2);

app/templates/crate/version.hbs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@
109109
<ul class='owners'>
110110
{{#each crate.owners as |owner|}}
111111
<li>
112-
{{#user-link user=owner}}
113-
{{user-avatar user=owner size='medium-small'}}
114-
{{/user-link}}
112+
{{#link-to 'user' owner.login}}
113+
{{user-avatar user=owner size='medium-small'}}
114+
{{/link-to}}
115115
</li>
116116
{{/each}}
117117
</ul>

app/templates/user.hbs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<div id='crates-heading'>
2+
{{user-avatar user=model.user size='medium'}}
3+
<h1>
4+
{{ model.user.login }}
5+
</h1>
6+
{{#user-link user=model.user}}
7+
<img alt="GitHub profile" title="GitHub profile" src="/assets/GitHub-Mark-32px.png"/>
8+
{{/user-link}}
9+
</div>
10+
11+
<div id='user-profile'>
12+
<div class='info'>
13+
{{! TODO: reduce duplication with templates/crates.hbs }}
14+
15+
<div id='results'>
16+
<div class='nav'>
17+
<span class='amt small'>
18+
Displaying
19+
<span class='cur'>{{ currentPageStart }}-{{ currentPageEnd }}</span>
20+
of <span class='total'>{{ totalItems }}</span> total results
21+
</span>
22+
</div>
23+
24+
<div class='sort'>
25+
<span class='small'>Sort by</span>
26+
{{#rl-dropdown-container class="dropdown-container"}}
27+
{{#rl-dropdown-toggle tagName="a" class="dropdown"}}
28+
<img class="sort" src="/assets/sort.png"/>
29+
{{ currentSortBy }}
30+
<span class='arrow'></span>
31+
{{/rl-dropdown-toggle}}
32+
33+
{{#rl-dropdown tagName="ul" class="dropdown" closeOnChildClick="a:link"}}
34+
<li>
35+
{{#link-to (query-params sort="alpha")}}
36+
Alphabetical
37+
{{/link-to}}
38+
</li>
39+
<li>
40+
{{#link-to (query-params sort="downloads")}}
41+
Downloads
42+
{{/link-to}}
43+
</li>
44+
{{/rl-dropdown}}
45+
{{/rl-dropdown-container}}
46+
</div>
47+
</div>
48+
49+
<div id='crates' class='white-rows'>
50+
{{#each model.crates as |crate|}}
51+
{{crate-row crate=crate}}
52+
{{/each}}
53+
</div>
54+
55+
<div class='pagination'>
56+
{{#link-to (query-params page=prevPage) class="prev" rel="prev" title="previous page"}}
57+
<img class="left-pag" src="/assets/left-pag.png"/>
58+
{{/link-to}}
59+
{{#each pages as |page|}}
60+
{{#link-to (query-params page=page)}}{{ page }}{{/link-to}}
61+
{{/each}}
62+
{{#link-to (query-params page=nextPage) class="next" rel="next" title="next page"}}
63+
<img class="right-pag" src="/assets/right-pag.png"/>
64+
{{/link-to}}
65+
</div>
66+
</div>
67+
</div>

public/assets/GitHub-Mark-32px.png

1.67 KB
Loading

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ pub fn middleware(app: Arc<App>) -> MiddlewareBuilder {
100100
api_router.get("/versions/:version_id", C(version::show));
101101
api_router.get("/keywords", C(keyword::index));
102102
api_router.get("/keywords/:keyword_id", C(keyword::show));
103+
api_router.get("/users/:user_id", C(user::show));
103104
let api_router = Arc::new(R404(api_router));
104105

105106
let mut router = RouteBuilder::new();

src/user/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::HashMap;
22

33
use conduit::{Request, Response};
44
use conduit_cookie::{RequestSession};
5+
use conduit_router::RequestParams;
56
use pg::GenericConnection;
67
use pg::rows::Row;
78
use pg::types::Slice;
@@ -288,6 +289,20 @@ pub fn me(req: &mut Request) -> CargoResult<Response> {
288289
Ok(req.json(&R{ user: user.clone().encodable(), api_token: token }))
289290
}
290291

292+
/// Handles the `GET /users/:user_id` route.
293+
pub fn show(req: &mut Request) -> CargoResult<Response> {
294+
let name = &req.params()["user_id"];
295+
let conn = try!(req.tx());
296+
let user = try!(User::find_by_login(conn, &name));
297+
298+
#[derive(RustcEncodable)]
299+
struct R {
300+
user: EncodableUser,
301+
}
302+
Ok(req.json(&R{ user: user.clone().encodable() }))
303+
}
304+
305+
291306
/// Handles the `GET /me/updates` route.
292307
pub fn updates(req: &mut Request) -> CargoResult<Response> {
293308
let user = try!(req.user());

0 commit comments

Comments
 (0)