Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show user details. #416

Merged
merged 14 commits into from
Sep 28, 2016
23 changes: 23 additions & 0 deletions app/controllers/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Ember from 'ember';

const TO_SHOW = 5;
const { computed } = Ember;

export default Ember.Controller.extend({
init() {
this._super(...arguments);

this.fetchingFeed = true;
this.loadingMore = false;
this.hasMore = false;
this.crates = [];
},

visibleCrates: computed('crates', function() {
return this.get('crates').slice(0, TO_SHOW);
}),

hasMoreCrates: computed('crates', function() {
return this.get('crates.length') > TO_SHOW;
})
});
18 changes: 18 additions & 0 deletions app/controllers/user/crates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Ember from 'ember';
import PaginationMixin from '../../mixins/pagination';

const { computed } = Ember;
// TODO: reduce duplicatoin with controllers/crates
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small note here; eventually, controllers are going away in Ember, so this might be extra-fine for now :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah; I've been trying to train myself out of them, with little success so far!


export default Ember.Controller.extend(PaginationMixin, {
queryParams: ['page', 'per_page', 'sort'],
page: '1',
per_page: 10,
sort: 'alpha',

totalItems: computed.readOnly('model.crates.meta.total'),

currentSortBy: computed('sort', function() {
return (this.get('sort') === 'downloads') ? 'Downloads' : 'Alphabetical';
}),
});
3 changes: 3 additions & 0 deletions app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Router.map(function() {
this.route('crates');
this.route('following');
});
this.route('user', { path: '/users/:user_id' }, function() {
this.route('crates');
});
this.route('install');
this.route('search');
this.route('dashboard');
Expand Down
31 changes: 31 additions & 0 deletions app/routes/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Ember from 'ember';

export default Ember.Route.extend({
data: {},

setupController(controller, model) {
this._super(controller, model);

controller.set('fetchingFeed', true);
controller.set('crates', this.get('data.crates'));
},

model(params) {
return this.store.find('user', params.user_id).catch(e => {
if (e.errors.any(e => e.detail === 'Not Found')) {
this.controllerFor('application').set('nextFlashError', `User '${params.user_id}' does not exist`);
return this.replaceWith('index');
}
});
},

afterModel(user) {
let crates = this.store.query('crate', {
user_id: user.get('id')
});

return Ember.RSVP.hash({
crates,
}).then((hash) => this.set('data', hash));
}
});
30 changes: 30 additions & 0 deletions app/routes/user/crates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Ember from 'ember';

export default Ember.Route.extend({
queryParams: {
page: { refreshModel: true },
sort: { refreshModel: true },
},

model(params) {
const { user_id } = this.paramsFor('user');
return this.store.find('user', user_id).then(
(user) => {
params.user_id = user.get('id');
return Ember.RSVP.hash({
crates: this.store.query('crate', params),
user
});
},
(e) => {
if (e.errors.any(e => e.detail === 'Not Found')) {
this
.controllerFor('application')
.set('nextFlashError', `User '${params.user_id}' does not exist`);
return this.replaceWith('index');
}
}
);
},
});

16 changes: 16 additions & 0 deletions app/templates/user.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div id='crates-heading'>
{{#user-link user=model}}
{{user-avatar user=model size='medium'}}
{{/user-link}}
<h1>
{{#link-to 'user' model}}
{{ model.login }}
{{/link-to}}
</h1>
</div>

<div id='user-profile'>
<div class='info'>
{{outlet}}
</div>
</div>
53 changes: 53 additions & 0 deletions app/templates/user/crates.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{{! TODO: reduce duplication with templates/crates.hbs }}

<div id='results'>
<div class='nav'>
<span class='amt small'>
Displaying
<span class='cur'>{{ currentPageStart }}-{{ currentPageEnd }}</span>
of <span class='total'>{{ totalItems }}</span> total results
</span>
</div>

<div class='sort'>
<span class='small'>Sort by</span>
{{#rl-dropdown-container class="dropdown-container"}}
{{#rl-dropdown-toggle tagName="a" class="dropdown"}}
<img class="sort" src="/assets/sort.png"/>
{{ currentSortBy }}
<span class='arrow'></span>
{{/rl-dropdown-toggle}}

{{#rl-dropdown tagName="ul" class="dropdown" closeOnChildClick="a:link"}}
<li>
{{#link-to (query-params sort="alpha")}}
Alphabetical
{{/link-to}}
</li>
<li>
{{#link-to (query-params sort="downloads")}}
Downloads
{{/link-to}}
</li>
{{/rl-dropdown}}
{{/rl-dropdown-container}}
</div>
</div>

<div id='crates' class='white-rows'>
{{#each model.crates as |crate|}}
{{crate-row crate=crate}}
{{/each}}
</div>

<div class='pagination'>
{{#link-to (query-params page=prevPage) class="prev" rel="prev" title="previous page"}}
<img class="left-pag" src="/assets/left-pag.png"/>
{{/link-to}}
{{#each pages as |page|}}
{{#link-to (query-params page=page)}}{{ page }}{{/link-to}}
{{/each}}
{{#link-to (query-params page=nextPage) class="next" rel="next" title="next page"}}
<img class="right-pag" src="/assets/right-pag.png"/>
{{/link-to}}
</div>
7 changes: 7 additions & 0 deletions app/templates/user/index.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>
Generic profile information here.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what should we do about this? More in the main thread.

</p>

{{#link-to 'user.crates' model.login}}
See all their crates
{{/link-to}}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub fn middleware(app: Arc<App>) -> MiddlewareBuilder {
api_router.get("/versions/:version_id", C(version::show));
api_router.get("/keywords", C(keyword::index));
api_router.get("/keywords/:keyword_id", C(keyword::show));
api_router.get("/users/:user_id", C(user::show));
let api_router = Arc::new(R404(api_router));

let mut router = RouteBuilder::new();
Expand Down
15 changes: 15 additions & 0 deletions src/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::HashMap;

use conduit::{Request, Response};
use conduit_cookie::{RequestSession};
use conduit_router::RequestParams;
use pg::GenericConnection;
use pg::rows::Row;
use pg::types::Slice;
Expand Down Expand Up @@ -288,6 +289,20 @@ pub fn me(req: &mut Request) -> CargoResult<Response> {
Ok(req.json(&R{ user: user.clone().encodable(), api_token: token }))
}

/// Handles the `GET /users/:user_id` route.
pub fn show(req: &mut Request) -> CargoResult<Response> {
let name = &req.params()["user_id"];
let conn = try!(req.tx());
let user = try!(User::find_by_login(conn, &name));

#[derive(RustcEncodable)]
struct R {
user: EncodableUser,
}
Ok(req.json(&R{ user: user.clone().encodable() }))
}


/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut Request) -> CargoResult<Response> {
let user = try!(req.user());
Expand Down