Ember.js: User fixtures + injection + login

* Adding **user fixtures** for signin

* Adds an initializer for the **current logged in user**.
The created singleton object is injected into all controllers + routes.
It can be used inside routes + controllers with this.get('user').
For simple development the object is instanciated with a userFixture.
Once a proper login and api mock is in place, the fixture needs to be removed.

* Added **route 'login'** on url '/ghost/ember/signin'
* Added authenticated route with an error hook that redirects to the login route, if status 401 (unauthorized) is returned from REST API.
* All "secure" routes now extend from authenticated route
* Add /ghost/ember to noAuthNeeded routes in middleware
This commit is contained in:
Manuel Mitasch 2014-03-11 17:23:32 +01:00
parent 5313eb7bce
commit b1b15afc5e
12 changed files with 159 additions and 25 deletions

View File

@ -1,5 +1,6 @@
import Resolver from 'ember/resolver';
import initFixtures from 'ghost/fixtures/init';
import {currentUser, injectCurrentUser} from 'ghost/initializers/current-user';
var App = Ember.Application.extend({
/**
@ -16,4 +17,7 @@ var App = Ember.Application.extend({
initFixtures();
export default App;
App.initializer(currentUser);
App.initializer(injectCurrentUser);
export default App;

View File

@ -0,0 +1,5 @@
var ApplicationController = Ember.Controller.extend({
isLogin: Ember.computed.equal('currentPath', 'login')
});
export default ApplicationController;

View File

@ -1,32 +1,41 @@
/*global ic */
import postFixtures from 'ghost/fixtures/posts';
import userFixtures from 'ghost/fixtures/users';
var response = function (responseBody, status) {
status = status || 200;
var textStatus = (status === 200) ? 'success' : 'error';
var post = function (id) {
return {
response: postFixtures.findBy('id', id),
jqXHR: {},
textStatus: 'success'
response: responseBody,
jqXHR: { status: status },
textStatus: textStatus
};
};
var posts = function () {
return {
response: {
'posts': postFixtures,
'page': 1,
'limit': 15,
'pages': 1,
'total': 2
},
jqXHR: {},
textStatus: 'success'
};
var user = function (status) {
return response(userFixtures.findBy('id', 1), status);
};
var defineFixtures = function () {
ic.ajax.defineFixture('/ghost/api/v0.1/posts', posts());
ic.ajax.defineFixture('/ghost/api/v0.1/posts/1', post(1));
ic.ajax.defineFixture('/ghost/api/v0.1/posts/2', post(2));
var post = function (id, status) {
return response(postFixtures.findBy('id', id), status);
};
var posts = function (status) {
return response({
'posts': postFixtures,
'page': 1,
'limit': 15,
'pages': 1,
'total': 2
}, status);
};
var defineFixtures = function (status) {
ic.ajax.defineFixture('/ghost/api/v0.1/posts', posts(status));
ic.ajax.defineFixture('/ghost/api/v0.1/posts/1', post(1, status));
ic.ajax.defineFixture('/ghost/api/v0.1/posts/2', post(2, status));
ic.ajax.defineFixture('/ghost/api/v0.1/signin', user(status));
};
export default defineFixtures;

View File

@ -0,0 +1,23 @@
var users = [
{
"id": 1,
"uuid": "ba9c67e4-8046-4b8c-9349-0eed3cca7529",
"name": "some-user",
"slug": "some-user",
"email": "some@email.com",
"image": null,
"cover": null,
"bio": "",
"website": "",
"location": "",
"accessibility": null,
"status": "active",
"language": "en_US",
"meta_title": null,
"meta_description": null,
"created_at": "2014-02-15T20:02:25.000Z",
"updated_at": "2014-03-11T14:06:43.000Z"
}
];
export default users;

View File

@ -0,0 +1,26 @@
import userFixtures from 'ghost/fixtures/users';
var currentUser = {
name: 'currentUser',
initialize: function (container) {
var userFixture = userFixtures.findBy("id", 1);
container.register('user:current', Ember.Object.extend(userFixture));
// Todo: remove userFixture
// Todo: use model User instead of Ember.Object once model layer exists
}
};
var injectCurrentUser = {
name: 'injectCurrentUser',
initialize: function (container) {
if (container.lookup('user:current')) {
container.injection('route', 'user', 'user:current');
container.injection('controller', 'user', 'user:current');
}
}
};
export {currentUser, injectCurrentUser};

View File

@ -9,6 +9,7 @@ Router.reopen({
});
Router.map(function () {
this.route('login', { path: '/signin' });
this.resource('posts', { path: '/' }, function () {
this.route('post', { path: ':post_id' });
});

View File

@ -0,0 +1,11 @@
var AuthenticatedRoute = Ember.Route.extend({
actions: {
error: function (error) {
if (error.jqXHR.status === 401) {
this.transitionTo('login');
}
}
}
});
export default AuthenticatedRoute;

View File

@ -1,7 +1,8 @@
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
import AuthenticatedRoute from 'ghost/routes/authenticated';
var EditorRoute = Ember.Route.extend(styleBody, {
var EditorRoute = AuthenticatedRoute.extend(styleBody, {
classNames: ['editor'],
model: function (params) {

View File

@ -0,0 +1,32 @@
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
var isEmpty = Ember.isEmpty;
var LoginRoute = Ember.Route.extend(styleBody, {
classNames: ['ghost-login'],
actions: {
login: function () {
var self = this,
controller = this.get('controller'),
data = controller.getProperties('email', 'password');
if (!isEmpty(data.email) && !isEmpty(data.password)) {
ajax('/ghost/api/v0.1/signin', data).then(
function (response) {
self.set('user', response);
self.transitionTo('posts');
}, function () {
window.alert('Error'); // Todo Show notification
}
);
} else {
window.alert('Must enter email + passwort. Todo: Must show as notification'); // Todo Show notification
}
}
}
});
export default LoginRoute;

View File

@ -1,7 +1,8 @@
import ajax from 'ghost/utils/ajax';
import styleBody from 'ghost/mixins/style-body';
import AuthenticatedRoute from 'ghost/routes/authenticated';
var PostsRoute = Ember.Route.extend(styleBody, {
var PostsRoute = AuthenticatedRoute.extend(styleBody, {
classNames: ['manage'],
model: function () {

View File

@ -1,5 +1,7 @@
{{partial "navbar"}}
{{#unless isLogin}}
{{partial "navbar"}}
{{/unless}}
<main role="main" id="main">
{{outlet}}
</main>
</main>

View File

@ -0,0 +1,19 @@
<main role="main" id="main">
<aside id="notifications" class="notifications">
</aside>
<section class="login-box js-login-box" style="opacity: 1;">
<form id="login" class="login-form" method="post" novalidate="novalidate">
<div class="email-wrap">
{{input class="email" type="email" placeholder="Email Address" name="email" autocapitalize="off" autocorrect="off" value=email}}
</div>
<div class="password-wrap">
{{input class="password" type="password" placeholder="Password" name="password" value=password}}
</div>
<button class="button-save" type="submit" {{action "login"}}>Log in</button>
<section class="meta">
<a class="forgotten-password" href="/ghost/forgotten/">Forgotten password?</a>
</section>
</form>
</section>
</main>