Skip to content

Frontend page for listing pending owner invites #1057

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

Merged
merged 12 commits into from
Sep 18, 2017
Merged
8 changes: 8 additions & 0 deletions app/adapters/crate-owner-invite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import DS from 'ember-data';

export default DS.RESTAdapter.extend({
namespace: 'api/v1/me',
pathForType() {
return 'crate_owner_invitations';
}
});
8 changes: 8 additions & 0 deletions app/models/crate-owner-invite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import DS from 'ember-data';

export default DS.Model.extend({
invited_by_username: DS.attr('string'),
crate_name: DS.attr('string'),
crate_id: DS.attr('number'),
created_at: DS.attr('date')
});
1 change: 1 addition & 0 deletions app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Router.map(function() {
this.route('me', function() {
this.route('crates');
this.route('following');
this.route('pending-invites');
});
this.route('user', { path: '/users/:user_id' });
this.route('install');
Expand Down
9 changes: 9 additions & 0 deletions app/routes/me/pending-invites.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Ember from 'ember';

import AuthenticatedRoute from '../../mixins/authenticated-route';

export default Ember.Route.extend(AuthenticatedRoute, {
model() {
return this.get('store').findAll('crate-owner-invite');
}
});
8 changes: 8 additions & 0 deletions app/serializers/crate-owner-invite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
primaryKey: 'crate_id',
modelNameFromPayloadKey() {
return 'crate-owner-invite';
}
});
18 changes: 18 additions & 0 deletions app/styles/me.scss
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
#my-crates, #my-following { margin: 0; }
}
}

#my-feed {
@include flex-grow(5);
h2 { font-size: 105%; }
Expand Down Expand Up @@ -129,6 +130,23 @@
}
}

#my-invites {
@include flex-grow(5);

.row {
@include display-flex;
@include flex-direction(column);
}

.info {
@include display-flex;
@include align-items(baseline);
@include justify-content(space-between);

.date { @include flex-grow(2); text-align: right; }
}
}

#stats {
margin-left: auto;
padding: 10px;
Expand Down
38 changes: 38 additions & 0 deletions app/templates/me/pending-invites.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{ title 'Pending Invites' }}

<div id='crates-heading'>
{{svg-jar "gear"}}
<h1>Pending Owner Invites</h1>
</div>

<div id='my-invites'>
<div class='white-rows'>
{{#each model as |invite|}}
<div class='row'>
<div class='info'>
<div class='name'>
<h3>
{{#link-to 'crate' invite.crate_name}}
{{invite.crate_name}}
{{/link-to}}
</h3>
</div>
<div class='invite'>
<p>Invited by:
{{#link-to 'user' invite.invited_by_username}}
{{invite.invited_by_username}}
{{/link-to}}
</p>
</div>
<div class='sent'>
<span class='small'>{{moment-from-now invite.created_at}}</span>
</div>
<div class='actions'>
<button class='small yellow-button'>Accept</button>
<button class='small yellow-button'>Deny</button>
</div>
</div>
</div>
{{/each}}
</div>
</div>
6 changes: 3 additions & 3 deletions src/crate_owner_invitation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub fn list(req: &mut Request) -> CargoResult<Response> {
let conn = &*req.db_conn()?;
let user_id = req.user()?.id;

let invitations = crate_owner_invitations::table
let crate_owner_invitations = crate_owner_invitations::table
.filter(crate_owner_invitations::invited_user_id.eq(user_id))
.load::<CrateOwnerInvitation>(&*conn)?
.into_iter()
Expand All @@ -76,7 +76,7 @@ pub fn list(req: &mut Request) -> CargoResult<Response> {

#[derive(Serialize)]
struct R {
invitations: Vec<EncodableCrateOwnerInvitation>,
crate_owner_invitations: Vec<EncodableCrateOwnerInvitation>,
}
Ok(req.json(&R { invitations }))
Ok(req.json(&R { crate_owner_invitations }))
}
17 changes: 10 additions & 7 deletions src/tests/owners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn check_ownership_one_crate() {
fn invitations_are_empty_by_default() {
#[derive(Deserialize)]
struct R {
invitations: Vec<EncodableCrateOwnerInvitation>,
crate_owner_invitations: Vec<EncodableCrateOwnerInvitation>,
}

let (_b, app, middle) = ::app();
Expand All @@ -322,14 +322,14 @@ fn invitations_are_empty_by_default() {
let mut response = ok_resp!(middle.call(&mut req));
let json: R = ::json(&mut response);

assert_eq!(json.invitations.len(), 0);
assert_eq!(json.crate_owner_invitations.len(), 0);
}

#[test]
fn invitations_list() {
#[derive(Deserialize)]
struct R {
invitations: Vec<EncodableCrateOwnerInvitation>,
crate_owner_invitations: Vec<EncodableCrateOwnerInvitation>,
}

let (_b, app, middle) = ::app();
Expand Down Expand Up @@ -362,8 +362,11 @@ fn invitations_list() {
let mut response = ok_resp!(middle.call(&mut req));
let json: R = ::json(&mut response);

assert_eq!(json.invitations.len(), 1);
assert_eq!(json.invitations[0].invited_by_username, "inviting_user");
assert_eq!(json.invitations[0].crate_name, "invited_crate");
assert_eq!(json.invitations[0].crate_id, krate.id);
assert_eq!(json.crate_owner_invitations.len(), 1);
assert_eq!(
json.crate_owner_invitations[0].invited_by_username,
"inviting_user"
);
assert_eq!(json.crate_owner_invitations[0].crate_name, "invited_crate");
assert_eq!(json.crate_owner_invitations[0].crate_id, krate.id);
}