From 2d7d22f8478a402bdaf3458c33f0f3d17c95c9ee Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 5 Nov 2015 17:42:50 -0700 Subject: [PATCH 1/8] Set up preliminary tests for users --- app/mirage/config.js | 3 + app/pods/protected/users/index/template.hbs | 2 +- .../protected/users/user-form/template.hbs | 4 +- app/pods/users/new/template.hbs | 10 +-- tests/acceptance/users-test.js | 77 +++++++++++++++++++ 5 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 tests/acceptance/users-test.js diff --git a/app/mirage/config.js b/app/mirage/config.js index 929ea8a..c03b469 100644 --- a/app/mirage/config.js +++ b/app/mirage/config.js @@ -10,7 +10,10 @@ export function testConfig() { this.namespace = '/api/hymenobacter'; this.timing = 0; + this.get('/users'); + this.post('/users'); this.get('/users/:id'); + this.put('/users/:id'); this.get('/species'); this.post('/species'); diff --git a/app/pods/protected/users/index/template.hbs b/app/pods/protected/users/index/template.hbs index adb5b55..5354e95 100644 --- a/app/pods/protected/users/index/template.hbs +++ b/app/pods/protected/users/index/template.hbs @@ -1,5 +1,5 @@

{{genus-name}} Users

-

Total users: {{model.length}}

+

Total users: {{model.length}}

diff --git a/app/pods/protected/users/user-form/template.hbs b/app/pods/protected/users/user-form/template.hbs index c6209a9..e7a8b02 100644 --- a/app/pods/protected/users/user-form/template.hbs +++ b/app/pods/protected/users/user-form/template.hbs @@ -4,7 +4,7 @@
- {{input value=user.name}} + {{input value=user.name class="user-name"}}
@@ -33,7 +33,7 @@ Cancel {{#if user.hasDirtyAttributes}} - {{/if}} diff --git a/app/pods/users/new/template.hbs b/app/pods/users/new/template.hbs index d6e81c5..e8e6e2c 100644 --- a/app/pods/users/new/template.hbs +++ b/app/pods/users/new/template.hbs @@ -6,22 +6,22 @@
- - - - - - - - - - {{#each model as |row|}} - - - - - - - {{/each}} - -
NameEmailRoleDate Registered
- {{#link-to 'protected.users.show' row}} - {{row.name}} - {{/link-to}} - - {{row.email}} - - {{row.fullRole}} - - {{null-time row.createdAt 'LL'}} -
+{{ + protected/users/index/users-table + users=model +}} diff --git a/app/pods/protected/users/index/users-table/component.js b/app/pods/protected/users/index/users-table/component.js new file mode 100644 index 0000000..2abad45 --- /dev/null +++ b/app/pods/protected/users/index/users-table/component.js @@ -0,0 +1,7 @@ +import Ember from 'ember'; + +const { Component } = Ember; + +export default Component.extend({ + users: null, +}); diff --git a/app/pods/protected/users/index/users-table/template.hbs b/app/pods/protected/users/index/users-table/template.hbs new file mode 100644 index 0000000..ad2a064 --- /dev/null +++ b/app/pods/protected/users/index/users-table/template.hbs @@ -0,0 +1,33 @@ + +

Total users: {{users.length}}

+ + + + + + + + + + + + {{#each users as |user|}} + + + + + + + {{/each}} + +
NameEmailRoleDate Registered
+ {{#link-to 'protected.users.show' user}} + {{user.name}} + {{/link-to}} + + {{user.email}} + + {{user.fullRole}} + + {{null-time user.createdAt 'LL'}} +
diff --git a/app/pods/protected/users/loading/template.hbs b/app/pods/protected/users/loading/template.hbs new file mode 100644 index 0000000..e5a3e05 --- /dev/null +++ b/app/pods/protected/users/loading/template.hbs @@ -0,0 +1 @@ +{{loading-panel}} From b742ddbb518c7fbb6b170edc07b584a6c9920eb8 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 5 Nov 2015 20:24:07 -0700 Subject: [PATCH 3/8] refactored users/show --- app/pods/protected/users/show/controller.js | 10 ++-- app/pods/protected/users/show/route.js | 16 +++-- app/pods/protected/users/show/template.hbs | 58 ++----------------- .../users/show/user-card/component.js | 11 ++++ .../users/show/user-card/template.hbs | 53 +++++++++++++++++ 5 files changed, 84 insertions(+), 64 deletions(-) create mode 100644 app/pods/protected/users/show/user-card/component.js create mode 100644 app/pods/protected/users/show/user-card/template.hbs diff --git a/app/pods/protected/users/show/controller.js b/app/pods/protected/users/show/controller.js index 3c6c549..26c243d 100644 --- a/app/pods/protected/users/show/controller.js +++ b/app/pods/protected/users/show/controller.js @@ -1,9 +1,9 @@ import Ember from 'ember'; +import DeleteModel from '../../../../mixins/delete-model'; -export default Ember.Controller.extend({ - currentUser: Ember.inject.service('session-account'), +const { Controller } = Ember; - isUser: Ember.computed('model.id', 'currentUser.account.id', function() { - return this.get('model.id') === this.get('currentUser.account.id'); - }), +export default Controller.extend(DeleteModel, { + // Required for DeleteModel mixin + transitionRoute: 'protected.index', }); diff --git a/app/pods/protected/users/show/route.js b/app/pods/protected/users/show/route.js index a0c9fd9..798787d 100644 --- a/app/pods/protected/users/show/route.js +++ b/app/pods/protected/users/show/route.js @@ -1,21 +1,25 @@ import Ember from 'ember'; -export default Ember.Route.extend({ - currentUser: Ember.inject.service('session-account'), +const { Route, inject: { service } } = Ember; +export default Route.extend({ + currentUser: service('session-account'), + + // Not using ElevatedAccess Mixin because the rules for viewing user accounts + // is slightly different. beforeModel: function(transition) { this._super(transition); - this.get('currentUser.account').then((currentUser) => { - let user_id = transition.params['protected.users.show'].user_id; - if (!currentUser.get('isAdmin') && currentUser.get('id') !== user_id) { + this.get('currentUser.account').then((user) => { + const user_id = transition.params['protected.users.show'].user_id; + if (!user.get('isAdmin') && user.get('id') !== user_id) { this.transitionTo('protected.users.index'); } }); }, model: function(params) { - return this.store.findRecord('user', params.user_id, { reload: true }); + return this.store.findRecord('user', params.user_id); }, }); diff --git a/app/pods/protected/users/show/template.hbs b/app/pods/protected/users/show/template.hbs index ca89688..a8648c4 100644 --- a/app/pods/protected/users/show/template.hbs +++ b/app/pods/protected/users/show/template.hbs @@ -1,53 +1,5 @@ -
-
- - {{model.name}} - - - {{! ROW 1 }} -
-
-
Email
-
- {{model.email}} -
-
-
-
Role
-
- {{model.fullRole}} -
-
-
- - {{! ROW 2 }} -
-
-
Record Created
-
{{null-time model.createdAt 'LL'}}
-
-
-
Record Updated
-
{{null-time model.updatedAt 'LL'}}
-
-
-
-
-
-
- {{#if isUser}} -
- {{#link-to 'protected.users.changepassword' model.id class="button-gray smaller"}} - Change Password - {{/link-to}} -
- {{/if}} - -
- {{#if model.canEdit}} - {{#link-to 'protected.users.edit' model.id class="button-gray smaller"}} - Edit - {{/link-to}} - {{/if}} -
-
+{{ + protected/users/show/user-card + user=model + on-delete=(action 'delete') +}} diff --git a/app/pods/protected/users/show/user-card/component.js b/app/pods/protected/users/show/user-card/component.js new file mode 100644 index 0000000..41dcaef --- /dev/null +++ b/app/pods/protected/users/show/user-card/component.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +const { Component, computed, inject: { service } } = Ember; + +export default Component.extend({ + currentUser: service('session-account'), + + isUser: computed('model.id', 'currentUser.account.id', function() { + return this.get('model.id') === this.get('currentUser.account.id'); + }), +}); diff --git a/app/pods/protected/users/show/user-card/template.hbs b/app/pods/protected/users/show/user-card/template.hbs new file mode 100644 index 0000000..6aa0d84 --- /dev/null +++ b/app/pods/protected/users/show/user-card/template.hbs @@ -0,0 +1,53 @@ +
+
+ + {{user.name}} + + + {{! ROW 1 }} +
+
+
Email
+
+ {{user.email}} +
+
+
+
Role
+
+ {{user.fullRole}} +
+
+
+ + {{! ROW 2 }} +
+
+
Record Created
+
{{null-time user.createdAt 'LL'}}
+
+
+
Record Updated
+
{{null-time user.updatedAt 'LL'}}
+
+
+
+
+
+
+ {{#if isUser}} +
+ {{#link-to 'protected.users.changepassword' user.id class="button-gray smaller"}} + Change Password + {{/link-to}} +
+ {{/if}} + +
+ {{#if model.canEdit}} + {{#link-to 'protected.users.edit' user.id class="button-gray smaller"}} + Edit + {{/link-to}} + {{/if}} +
+
From 1dd0910ed1711e6025f580dd78550b865069badb Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 6 Nov 2015 11:20:28 -0700 Subject: [PATCH 4/8] Refactored users/edit --- app/helpers/equal.js | 4 +- app/mirage/config.js | 2 +- app/mixins/save-model.js | 1 + app/mixins/setup-metadata.js | 2 + .../characteristics/edit/controller.js | 2 +- app/pods/protected/users/edit/controller.js | 42 +++------------ app/pods/protected/users/edit/route.js | 10 ++-- app/pods/protected/users/edit/template.hbs | 5 +- .../users/show/user-card/component.js | 6 ++- .../users/show/user-card/template.hbs | 2 +- .../protected/users/user-form/component.js | 54 +++++++++++++++++-- .../protected/users/user-form/template.hbs | 16 +++--- app/services/session-account.js | 11 ++-- 13 files changed, 92 insertions(+), 65 deletions(-) diff --git a/app/helpers/equal.js b/app/helpers/equal.js index db3e867..a003400 100644 --- a/app/helpers/equal.js +++ b/app/helpers/equal.js @@ -1,7 +1,9 @@ import Ember from 'ember'; +const { Helper: { helper } } = Ember; + export function equalHelper(params) { return params[0] === params[1]; } -export default Ember.HTMLBars.makeBoundHelper(equalHelper); +export default helper(equalHelper); diff --git a/app/mirage/config.js b/app/mirage/config.js index c03b469..3982c0c 100644 --- a/app/mirage/config.js +++ b/app/mirage/config.js @@ -2,7 +2,7 @@ export default function() { // Don't use mirage for development (for now) this.urlPrefix = 'http://127.0.0.1:8901'; this.namespace = '/api'; - this.passthrough(); + this.passthrough('http://localhost:4200/**', 'http://127.0.0.1:8901/**'); } export function testConfig() { diff --git a/app/mixins/save-model.js b/app/mixins/save-model.js index 53efda9..8d3b233 100644 --- a/app/mixins/save-model.js +++ b/app/mixins/save-model.js @@ -16,6 +16,7 @@ export default Mixin.create({ if (model.get('hasDirtyAttributes')) { model.save().then((model) => { + this.get('flashMessages').clearMessages(); this.transitionToRoute(fallbackRoute, model); }, () => { ajaxError(model.get('errors'), this.get('flashMessages')); diff --git a/app/mixins/setup-metadata.js b/app/mixins/setup-metadata.js index 183f93f..bdfd886 100644 --- a/app/mixins/setup-metadata.js +++ b/app/mixins/setup-metadata.js @@ -5,10 +5,12 @@ const { Mixin, inject: { service }} = Ember; export default Mixin.create({ currentUser: service('session-account'), metaData: null, + isAdmin: null, setupMetaDataOnInit: Ember.on('init', function() { this.get('currentUser.account').then((user) => { this.set('metaData', user.get('metaData')); + this.set('isAdmin', user.get('isAdmin')); }); }), }); diff --git a/app/pods/protected/characteristics/edit/controller.js b/app/pods/protected/characteristics/edit/controller.js index 0b83924..aff45e1 100644 --- a/app/pods/protected/characteristics/edit/controller.js +++ b/app/pods/protected/characteristics/edit/controller.js @@ -6,5 +6,5 @@ const { Controller } = Ember; export default Controller.extend(SaveModel, { // Required for SaveModel mixin fallbackRouteSave: 'protected.characteristics.show', - fallbackRouteCancel: 'protected.characteristics.index', + fallbackRouteCancel: 'protected.characteristics.show', }); diff --git a/app/pods/protected/users/edit/controller.js b/app/pods/protected/users/edit/controller.js index 955c328..283631c 100644 --- a/app/pods/protected/users/edit/controller.js +++ b/app/pods/protected/users/edit/controller.js @@ -1,40 +1,10 @@ import Ember from 'ember'; -import ajaxError from '../../../../utils/ajax-error'; +import SaveModel from '../../../../mixins/save-model'; -export default Ember.Controller.extend({ - actions: { - save: function() { - let user = this.get('model'); +const { Controller } = Ember; - if (user.get('hasDirtyAttributes')) { - let attrs = user.changedAttributes(), roleChanged = false; - if (attrs.role) { - roleChanged = true; - } - user.save().then((user) => { - this.get('flashMessages').clearMessages(); - if (roleChanged) { - // Need to clear the store so that canEdit and canAdd - // attributes reflect the new role. - this.get('store').unloadAll(); - } - this.transitionToRoute('protected.users.show', user); - }, () => { - ajaxError(user.get('errors'), this.get('flashMessages')); - }); - } else { - this.transitionToRoute('protected.users.show', user); - } - }, - - cancel: function() { - let user = this.get('model'); - - user.get('errors').clear(); - user.rollbackAttributes(); - - this.transitionToRoute('protected.users.show', user); - }, - - }, +export default Controller.extend(SaveModel, { + // Required for SaveModel mixin + fallbackRouteSave: 'protected.users.show', + fallbackRouteCancel: 'protected.users.show', }); diff --git a/app/pods/protected/users/edit/route.js b/app/pods/protected/users/edit/route.js index b95bdb2..c91288e 100644 --- a/app/pods/protected/users/edit/route.js +++ b/app/pods/protected/users/edit/route.js @@ -1,8 +1,12 @@ import Ember from 'ember'; -export default Ember.Route.extend({ - currentUser: Ember.inject.service('session-account'), +const { Route, inject: { service } } = Ember; +export default Route.extend({ + currentUser: service('session-account'), + + // Not using ElevatedAccess Mixin because the rules for viewing user accounts + // is slightly different. beforeModel: function(transition) { this._super(transition); @@ -16,7 +20,7 @@ export default Ember.Route.extend({ }, model: function(params) { - return this.store.findRecord('user', params.user_id, { reload: true }); + return this.store.findRecord('user', params.user_id); }, }); diff --git a/app/pods/protected/users/edit/template.hbs b/app/pods/protected/users/edit/template.hbs index e53c6e8..60cbe0d 100644 --- a/app/pods/protected/users/edit/template.hbs +++ b/app/pods/protected/users/edit/template.hbs @@ -1,7 +1,6 @@ {{ protected/users/user-form user=model - currentUser=currentUser.account - save="save" - cancel="cancel" + on-save=(action "save") + on-cancel=(action "cancel") }} diff --git a/app/pods/protected/users/show/user-card/component.js b/app/pods/protected/users/show/user-card/component.js index 41dcaef..00e3164 100644 --- a/app/pods/protected/users/show/user-card/component.js +++ b/app/pods/protected/users/show/user-card/component.js @@ -5,7 +5,9 @@ const { Component, computed, inject: { service } } = Ember; export default Component.extend({ currentUser: service('session-account'), - isUser: computed('model.id', 'currentUser.account.id', function() { - return this.get('model.id') === this.get('currentUser.account.id'); + user: null, + + isUser: computed('user.id', 'currentUser.account.id', function() { + return this.get('user.id') === this.get('currentUser.account.id'); }), }); diff --git a/app/pods/protected/users/show/user-card/template.hbs b/app/pods/protected/users/show/user-card/template.hbs index 6aa0d84..5ced125 100644 --- a/app/pods/protected/users/show/user-card/template.hbs +++ b/app/pods/protected/users/show/user-card/template.hbs @@ -44,7 +44,7 @@ {{/if}}
- {{#if model.canEdit}} + {{#if user.canEdit}} {{#link-to 'protected.users.edit' user.id class="button-gray smaller"}} Edit {{/link-to}} diff --git a/app/pods/protected/users/user-form/component.js b/app/pods/protected/users/user-form/component.js index 0a706f3..28fb03a 100644 --- a/app/pods/protected/users/user-form/component.js +++ b/app/pods/protected/users/user-form/component.js @@ -1,15 +1,61 @@ import Ember from 'ember'; +import SetupMetaData from '../../../../mixins/setup-metadata'; -export default Ember.Component.extend({ +const { Component } = Ember; + +export default Component.extend(SetupMetaData, { + // Read-only attributes + user: null, + isDirty: false, roles: Ember.String.w('A R W'), + // Actions + "on-save": null, + "on-cancel": null, + "on-update": null, + + // Property mapping + propertiesList: ['name', 'email', 'role'], + name: null, + email: null, + role: null, + + resetOnInit: Ember.on('init', function() { + this.get('propertiesList').forEach((field) => { + const valueInUser = this.get('user').get(field); + this.set(field, valueInUser); + }); + }), + + updateField: function(property, value) { + this.set(property, value); + // Manually compare against passed in value + if (this.get('user').get(property) !== value) { + this.set('isDirty', true); + } else { + this.set('isDirty', false); + } + }, + actions: { save: function() { - this.sendAction('save'); + return this.attrs['on-save'](this.getProperties(this.get('propertiesList'))); }, cancel: function() { - this.sendAction('cancel'); + return this.attrs['on-cancel'](); }, - } + + nameDidChange: function(value) { + this.updateField('name', value); + }, + + emailDidChange: function(value) { + this.updateField('email', value); + }, + + roleDidChange: function(value) { + this.updateField('role', value); + }, + }, }); diff --git a/app/pods/protected/users/user-form/template.hbs b/app/pods/protected/users/user-form/template.hbs index e7a8b02..cb0e27f 100644 --- a/app/pods/protected/users/user-form/template.hbs +++ b/app/pods/protected/users/user-form/template.hbs @@ -1,29 +1,29 @@
- {{user.name}} + {{name}}
- {{input value=user.name class="user-name"}} + {{one-way-input type="text" class="user-name" value=name update=(action "nameDidChange")}}
- {{input value=user.email}} + {{one-way-input type="text" class="email" value=email update=(action "emailDidChange")}}
- {{#if session.currentUser.isAdmin}} - {{#each roles as |roleChoice|}} - + {{/each}} {{else}} - {{user.role}} + {{role}} {{!-- Not editable --}} {{/if}}
@@ -32,7 +32,7 @@ Cancel - {{#if user.hasDirtyAttributes}} + {{#if isDirty}} diff --git a/app/services/session-account.js b/app/services/session-account.js index 1b34554..ee09f3a 100644 --- a/app/services/session-account.js +++ b/app/services/session-account.js @@ -2,19 +2,20 @@ import Ember from 'ember'; import DS from 'ember-data'; import parseBase64 from '../utils/parse-base64'; -const { service } = Ember.inject; +const { Service, computed, isEmpty, inject: { service } } = Ember; +const { PromiseObject } = DS; -export default Ember.Service.extend({ +export default Service.extend({ session: service('session'), store: service(), - account: Ember.computed('session.data.authenticated.access_token', function() { + account: computed('session.data.authenticated.access_token', function() { const token = this.get('session.data.authenticated.access_token'); const claims = parseBase64(token); const id = claims['sub']; - if (!Ember.isEmpty(id)) { - return DS.PromiseObject.create({ + if (!isEmpty(id)) { + return PromiseObject.create({ promise: this.get('store').findRecord('user', id), }); } From 45703e67ee5aaac58e6b0ef43d064d80aa9182d3 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 6 Nov 2015 11:56:38 -0700 Subject: [PATCH 5/8] refactor user password change --- .../users/changepassword/controller.js | 31 +++++------ .../changepassword/password-form/component.js | 52 +++++++++++++++++++ .../changepassword/password-form/template.hbs | 29 +++++++++++ .../protected/users/changepassword/route.js | 11 ++-- .../users/changepassword/template.hbs | 29 ++--------- 5 files changed, 107 insertions(+), 45 deletions(-) create mode 100644 app/pods/protected/users/changepassword/password-form/component.js create mode 100644 app/pods/protected/users/changepassword/password-form/template.hbs diff --git a/app/pods/protected/users/changepassword/controller.js b/app/pods/protected/users/changepassword/controller.js index b8d100e..3aed813 100644 --- a/app/pods/protected/users/changepassword/controller.js +++ b/app/pods/protected/users/changepassword/controller.js @@ -1,33 +1,30 @@ import Ember from 'ember'; import ajaxRequest from '../../../../utils/ajax-request'; -export default Ember.Controller.extend({ - session: Ember.inject.service('session'), - currentUser: Ember.inject.service('session-account'), +const { Controller, inject: { service } } = Ember; - passwordConfirm: null, +export default Controller.extend({ + session: service(), + currentUser: service('session-account'), actions: { - save: function() { - if (this.get('password') !== this.get('passwordConfirm')) { - this.get('flashMessages').clearMessages(); - this.get('flashMessages').error("Password fields don't match"); - return; - } - - let url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/password`; - let options = { + save: function(password) { + const url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/password`; + const id = this.get('currentUser.account.id'); + const options = { method: 'POST', data: { - id: this.get('currentUser.account.id'), - password: this.get('password'), + id: id, + password: password, }, }; ajaxRequest(url, options, this.get('session')); - this.transitionToRoute('protected.users.index'); + this.transitionToRoute('protected.users.show', id); this.get('flashMessages').information('Your password has been changed.'); }, + cancel: function() { + this.transitionToRoute('protected.users.show', this.get('currentUser.account.id')); + }, }, - }); diff --git a/app/pods/protected/users/changepassword/password-form/component.js b/app/pods/protected/users/changepassword/password-form/component.js new file mode 100644 index 0000000..494885e --- /dev/null +++ b/app/pods/protected/users/changepassword/password-form/component.js @@ -0,0 +1,52 @@ +import Ember from 'ember'; + +const { Component } = Ember; + +export default Component.extend({ + password: null, + passwordConfirm: null, + matches: false, + + // Actions + "on-save": null, + "on-cancel": null, + + updateField: function(property, value) { + this.set(property, value); + this.verifyPassword(this.get('password'), this.get('passwordConfirm')); + }, + + verifyPassword: function(password, passwordConfirm) { + if (password && passwordConfirm) { + if (password !== passwordConfirm) { + this.get('flashMessages').clearMessages(); + this.get('flashMessages').error("Password fields don't match"); + this.set('matches', false); + } else { + this.get('flashMessages').clearMessages(); + this.set('matches', true); + } + } + }, + + actions: { + save: function() { + this.verifyPassword(this.get('password'), this.get('passwordConfirm')); + if (this.get('matches')) { + return this.attrs['on-save'](this.get('password')); + } + }, + + cancel: function() { + return this.attrs['on-cancel'](); + }, + + passwordDidChange: function(value) { + this.updateField('password', value); + }, + + passwordConfirmDidChange: function(value) { + this.updateField('passwordConfirm', value); + }, + }, +}); diff --git a/app/pods/protected/users/changepassword/password-form/template.hbs b/app/pods/protected/users/changepassword/password-form/template.hbs new file mode 100644 index 0000000..5d30c35 --- /dev/null +++ b/app/pods/protected/users/changepassword/password-form/template.hbs @@ -0,0 +1,29 @@ +
+
+
+ Change password + +
    +
  • + + {{one-way-input type="password" class="password" value=password update=(action "passwordDidChange")}} +
  • +
  • + + {{one-way-input type="password" class="password-confirm" value=passwordConfirm update=(action "passwordConfirmDidChange")}} +
  • +
  • + + Cancel + + {{#if matches}} + + {{/if}} +
  • +
+ +
+
+
diff --git a/app/pods/protected/users/changepassword/route.js b/app/pods/protected/users/changepassword/route.js index ce869dd..f6da398 100644 --- a/app/pods/protected/users/changepassword/route.js +++ b/app/pods/protected/users/changepassword/route.js @@ -1,16 +1,19 @@ import Ember from 'ember'; -export default Ember.Route.extend({ - currentUser: Ember.inject.service('session-account'), +const { Route, inject: { service } } = Ember; + +export default Route.extend({ + currentUser: service('session-account'), beforeModel: function(transition) { this._super(transition); - let user_id = transition.params['protected.users.changepassword'].user_id; + // Only the logged in user can change their password + const user_id = transition.params['protected.users.changepassword'].user_id; this.get('currentUser.account').then((user) => { if (user.get('id') !== user_id) { - this.transitionTo('protected.users.index'); + this.transitionTo('protected.users.show', user.get('id')); } }); } diff --git a/app/pods/protected/users/changepassword/template.hbs b/app/pods/protected/users/changepassword/template.hbs index b22db6c..b7509c1 100644 --- a/app/pods/protected/users/changepassword/template.hbs +++ b/app/pods/protected/users/changepassword/template.hbs @@ -1,24 +1,5 @@ -
-
-
- Change password -
-
    -
  • - - {{input type="password" value=password}} -
  • -
  • - - {{input type="password" value=passwordConfirm}} -
  • -
  • - -
  • -
-
-
-
-
+{{ + protected/users/changepassword/password-form + on-save=(action "save") + on-cancel=(action "cancel") +}} From 367341c7803ebc5c4c6ca1817416a0685bdc3e35 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 10 Nov 2015 07:55:08 -0700 Subject: [PATCH 6/8] Lint user lockout --- app/pods/users/lockoutauthenticate/controller.js | 6 ++++-- app/pods/users/lockoutauthenticate/route.js | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/pods/users/lockoutauthenticate/controller.js b/app/pods/users/lockoutauthenticate/controller.js index 79734b5..4adee77 100644 --- a/app/pods/users/lockoutauthenticate/controller.js +++ b/app/pods/users/lockoutauthenticate/controller.js @@ -1,6 +1,8 @@ import Ember from 'ember'; -export default Ember.Controller.extend({ - queryParams: ['token'], +const { Controller } = Ember; +export default Controller.extend({ + queryParams: ['token'], + token: null, }); diff --git a/app/pods/users/lockoutauthenticate/route.js b/app/pods/users/lockoutauthenticate/route.js index 8ace7ef..21f807d 100644 --- a/app/pods/users/lockoutauthenticate/route.js +++ b/app/pods/users/lockoutauthenticate/route.js @@ -1,14 +1,16 @@ import Ember from 'ember'; import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin'; -export default Ember.Route.extend(UnauthenticatedRouteMixin, { - session: Ember.inject.service('session'), - currentUser: Ember.inject.service('session-account'), +const { Route, get, inject: { service } } = Ember; + +export default Route.extend(UnauthenticatedRouteMixin, { + session: service(), + currentUser: service('session-account'), beforeModel: function(transition) { this._super(transition); - let token = Ember.get(transition, 'queryParams.token'); + const token = get(transition, 'queryParams.token'); this.get('session').authenticate('authenticator:jwt-resolved', token).then(() => { this.get('currentUser.account').then((account) => { this.transitionTo('protected.users.changepassword', account.get('id')); From ec597cd419ab02633bc31194887d64dc7ac5176e Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 10 Nov 2015 09:15:28 -0700 Subject: [PATCH 7/8] Refactor new user creation --- app/pods/users/new/controller.js | 23 ++++--- app/pods/users/new/new-user-form/component.js | 66 +++++++++++++++++++ app/pods/users/new/new-user-form/template.hbs | 36 ++++++++++ app/pods/users/new/route.js | 13 ++-- app/pods/users/new/template.hbs | 38 ++--------- app/pods/users/new/verify/route.js | 19 ++---- app/pods/users/new/verify/template.hbs | 1 - 7 files changed, 130 insertions(+), 66 deletions(-) create mode 100644 app/pods/users/new/new-user-form/component.js create mode 100644 app/pods/users/new/new-user-form/template.hbs delete mode 100644 app/pods/users/new/verify/template.hbs diff --git a/app/pods/users/new/controller.js b/app/pods/users/new/controller.js index 3285b1a..e2bb0d8 100644 --- a/app/pods/users/new/controller.js +++ b/app/pods/users/new/controller.js @@ -1,30 +1,29 @@ import Ember from 'ember'; import ajaxError from '../../../utils/ajax-error'; -export default Ember.Controller.extend({ - passwordConfirm: null, +const { Controller } = Ember; + +export default Controller.extend({ + isLoading: false, actions: { - save: function() { - let user = this.get('user'); - - // All validation is server-side, except for password verification matching - if (user.get('password') !== this.get('passwordConfirm')) { - this.get('flashMessages').clearMessages(); - this.get('flashMessages').error("Password fields don't match"); - return; - } + save: function(properties) { + const user = this.get('model'); + user.setProperties(properties); if (user.get('hasDirtyAttributes')) { + this.set('isLoading', true); user.save().then(() => { - this.transitionTo('login').then(() => { + this.transitionToRoute('login').then(() => { this.get('flashMessages').information(`You have successfully signed up. Please check your email for further instructions.`); }); }, () => { + this.set('isLoading', false); ajaxError(user.get('errors'), this.get('flashMessages')); }); } }, + }, }); diff --git a/app/pods/users/new/new-user-form/component.js b/app/pods/users/new/new-user-form/component.js new file mode 100644 index 0000000..947080c --- /dev/null +++ b/app/pods/users/new/new-user-form/component.js @@ -0,0 +1,66 @@ +import Ember from 'ember'; + +const { Component } = Ember; + +export default Component.extend({ + // Read-only attributes + user: null, + isLoading: null, + + // Actions + "on-save": null, + "on-cancel": null, + + // Property mapping + propertiesList: ['name', 'email', 'password', 'passwordConfirm'], + name: null, + email: null, + password: null, + passwordConfirm: null, + + resetOnInit: Ember.on('init', function() { + this.get('propertiesList').forEach((field) => { + const valueInUser = this.get('user').get(field); + this.set(field, valueInUser); + }); + }), + + updateField: function(property, value) { + this.set(property, value); + // Manually compare against passed in value + if (this.get('user').get(property) !== value) { + this.set('isDirty', true); + } else { + this.set('isDirty', false); + } + }, + + actions: { + save: function() { + // All validation is server-side, except for password verification matching + if (this.get('password') !== this.get('passwordConfirm')) { + this.get('flashMessages').clearMessages(); + this.get('flashMessages').error("Password fields don't match"); + return; + } + + return this.attrs['on-save'](this.getProperties(this.get('propertiesList'))); + }, + + nameDidChange: function(value) { + this.updateField('name', value); + }, + + emailDidChange: function(value) { + this.updateField('email', value); + }, + + passwordDidChange: function(value) { + this.updateField('password', value); + }, + + passwordConfirmDidChange: function(value) { + this.updateField('passwordConfirm', value); + } + } +}); diff --git a/app/pods/users/new/new-user-form/template.hbs b/app/pods/users/new/new-user-form/template.hbs new file mode 100644 index 0000000..980eec9 --- /dev/null +++ b/app/pods/users/new/new-user-form/template.hbs @@ -0,0 +1,36 @@ +{{#if isLoading}} + {{loading-panel}} +{{else}} +
+
+
+ New User Signup +
+
    +
  • + + {{one-way-input type="text" class="user-name" value=name update=(action "nameDidChange")}} +
  • +
  • + + {{one-way-input type="text" class="email" value=email update=(action "emailDidChange")}} +
  • +
  • + + {{one-way-input type="password" class="password" value=password update=(action "passwordDidChange")}} +
  • +
  • + + {{one-way-input type="password" class="password-verify" value=passwordConfirm update=(action "passwordConfirmDidChange")}} +
  • +
  • + +
  • +
+
+
+
+
+{{/if}} diff --git a/app/pods/users/new/route.js b/app/pods/users/new/route.js index c3e757a..afdcdac 100644 --- a/app/pods/users/new/route.js +++ b/app/pods/users/new/route.js @@ -1,15 +1,10 @@ import Ember from 'ember'; import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin'; -export default Ember.Route.extend(UnauthenticatedRouteMixin, { +const { Route } = Ember; + +export default Route.extend(UnauthenticatedRouteMixin, { model: function() { - return Ember.RSVP.hash({ - user: this.store.createRecord('user'), - }); + return this.store.createRecord('user'); }, - - setupController: function(controller, model) { - controller.setProperties(model); - }, - }); diff --git a/app/pods/users/new/template.hbs b/app/pods/users/new/template.hbs index e8e6e2c..ac728bf 100644 --- a/app/pods/users/new/template.hbs +++ b/app/pods/users/new/template.hbs @@ -1,32 +1,6 @@ -
-
-
- New User Signup -
-
    -
  • - - {{input value=user.name class="user-name"}} -
  • -
  • - - {{input value=user.email class="email"}} -
  • -
  • - - {{input type="password" value=user.password class="password"}} -
  • -
  • - - {{input type="password" value=passwordConfirm class="password-verify"}} -
  • -
  • - -
  • -
-
-
-
-
+{{ + users/new/new-user-form + user=model + isLoading=isLoading + on-save=(action "save") +}} diff --git a/app/pods/users/new/verify/route.js b/app/pods/users/new/verify/route.js index 7c50823..06755b3 100644 --- a/app/pods/users/new/verify/route.js +++ b/app/pods/users/new/verify/route.js @@ -1,31 +1,26 @@ import Ember from 'ember'; import ajaxRequest from '../../../../utils/ajax-request'; -export default Ember.Route.extend({ - session: Ember.inject.service('session'), +const { Route, inject: { service } } = Ember; - apiURL: function() { - return this.get('globals.apiURL'); - }.property(), - - genus: function() { - return this.get('globals.genus'); - }.property(), +export default Route.extend({ + session: service(), + globals: service(), model: function(params) { - let url = `${this.get('apiURL')}/api/${this.get('genus')}/users/verify/${params.nonce}`; + const url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/verify/${params.nonce}`; return ajaxRequest(url, {}, this.get('session')); }, afterModel: function(model/*, transition*/) { - this.get('flashMessages').success(model.msg); + this.get('flashMessages').success(model.get('msg')); this.transitionTo('login'); }, actions: { error: function(error/*, transition*/) { - let err = Ember.$.parseJSON(error.responseText); + const err = Ember.$.parseJSON(error.responseText); this.get('flashMessages').error(err.error); this.transitionTo('login'); } diff --git a/app/pods/users/new/verify/template.hbs b/app/pods/users/new/verify/template.hbs deleted file mode 100644 index c24cd68..0000000 --- a/app/pods/users/new/verify/template.hbs +++ /dev/null @@ -1 +0,0 @@ -{{outlet}} From 079b2c59f61d8d048b15b9390e0ea8c0a2e63ae3 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Tue, 10 Nov 2015 09:22:35 -0700 Subject: [PATCH 8/8] Refactor user lockout/pw reset --- .../users/requestlockouthelp/controller.js | 15 ++++++++----- .../lockout-form/component.js | 18 +++++++++++++++ .../lockout-form/template.hbs | 18 +++++++++++++++ app/pods/users/requestlockouthelp/route.js | 8 ------- .../users/requestlockouthelp/template.hbs | 22 ++++--------------- 5 files changed, 49 insertions(+), 32 deletions(-) create mode 100644 app/pods/users/requestlockouthelp/lockout-form/component.js create mode 100644 app/pods/users/requestlockouthelp/lockout-form/template.hbs delete mode 100644 app/pods/users/requestlockouthelp/route.js diff --git a/app/pods/users/requestlockouthelp/controller.js b/app/pods/users/requestlockouthelp/controller.js index ccda273..2930b31 100644 --- a/app/pods/users/requestlockouthelp/controller.js +++ b/app/pods/users/requestlockouthelp/controller.js @@ -1,15 +1,18 @@ import Ember from 'ember'; import ajaxRequest from '../../../utils/ajax-request'; -export default Ember.Controller.extend({ - session: Ember.inject.service('session'), +const { Controller, inject: { service } } = Ember; + +export default Controller.extend({ + session: service(), + globals: service(), actions: { - save: function() { - let url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/lockout`; - let options = { + submit: function(email) { + const url = `${this.get('globals.apiURL')}/api/${this.get('globals.genus')}/users/lockout`; + const options = { method: 'POST', - data: { email: this.get('email') }, + data: { email: email }, }; ajaxRequest(url, options, this.get('session')); this.transitionToRoute('login'); diff --git a/app/pods/users/requestlockouthelp/lockout-form/component.js b/app/pods/users/requestlockouthelp/lockout-form/component.js new file mode 100644 index 0000000..2b7426f --- /dev/null +++ b/app/pods/users/requestlockouthelp/lockout-form/component.js @@ -0,0 +1,18 @@ +import Ember from 'ember'; + +const { Component } = Ember; + +export default Component.extend({ + email: null, + "on-submit": null, + + actions: { + save: function() { + return this.attrs["on-submit"](this.get('email')); + }, + + emailDidChange: function(value) { + this.set('email', value); + }, + } +}); diff --git a/app/pods/users/requestlockouthelp/lockout-form/template.hbs b/app/pods/users/requestlockouthelp/lockout-form/template.hbs new file mode 100644 index 0000000..5f18a09 --- /dev/null +++ b/app/pods/users/requestlockouthelp/lockout-form/template.hbs @@ -0,0 +1,18 @@ +
+
+
+ Account Lockout/Password Reset +
+
    +
  • + + {{one-way-input type="text" class="email" value=email update=(action "emailDidChange")}} +
  • +
  • + +
  • +
+
+
+
+
diff --git a/app/pods/users/requestlockouthelp/route.js b/app/pods/users/requestlockouthelp/route.js deleted file mode 100644 index 19831b4..0000000 --- a/app/pods/users/requestlockouthelp/route.js +++ /dev/null @@ -1,8 +0,0 @@ -import Ember from 'ember'; - -export default Ember.Route.extend({ - deactivate: function() { - this.controller.set('email', null); - }, - -}); diff --git a/app/pods/users/requestlockouthelp/template.hbs b/app/pods/users/requestlockouthelp/template.hbs index 7cdd25f..c482b70 100644 --- a/app/pods/users/requestlockouthelp/template.hbs +++ b/app/pods/users/requestlockouthelp/template.hbs @@ -1,18 +1,4 @@ -
-
-
- Account Lockout/Password Reset -
-
    -
  • - - {{input value=email}} -
  • -
  • - -
  • -
-
-
-
-
+{{ + users/requestlockouthelp/lockout-form + on-submit=(action "submit") +}}