1
0
mirror of https://github.com/flarum/core.git synced 2025-08-06 08:27:42 +02:00

Upgrade to L5 + huge refactor + more. closes #2

New stuff:
- Signup + email confirmation.
- Updated authentication strategy with remember cookies. closes #5
- New search system with some example gambits! This is cool - check out
the source. Fulltext drivers will be implemented as decorators
overriding the EloquentPostRepository’s findByContent method.
- Lay down the foundation for bootstrapping the Ember app.
- Update Web layer’s asset manager to properly publish CSS/JS files.
- Console commands to run installation migrations and seeds.

Refactoring:
- New structure: move models, repositories, commands, and events into
their own namespaces, rather than grouping by entity.
- All events are classes.
- Use L5 middleware and command bus implementations.
- Clearer use of repositories and the Active Record pattern.
Repositories are used only for retrieval of ActiveRecord objects, and
then save/delete operations are called directly on those ActiveRecords.
This way, we don’t over-abstract at the cost of Eloquent magic, but
testing is still easy.
- Refactor of Web layer so that it uses the Actions routing
architecture.
- “Actor” concept instead of depending on Laravel’s Auth.
- General cleanup!
This commit is contained in:
Toby Zerner
2015-02-24 20:33:18 +10:30
parent 330bff0ec8
commit 2733b5810d
266 changed files with 5562 additions and 4658 deletions

View File

@@ -1,9 +1,3 @@
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
"output-path": "../public"
}

View File

@@ -3,35 +3,26 @@ import config from '../config/environment';
export default Base.extend({
restore: function(data) {
var container = this.container;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.next(function() {
container.lookup('store:main').find('user', data.userId).then(function(user) {
resolve( { token: data.token, userId: data.userId, user: user } );
});
});
});
},
authenticate: function(credentials) {
var container = this.container;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
url: config.apiURL+'/auth/login',
url: config.baseURL+'login',
type: 'POST',
data: { identification: credentials.identification, password: credentials.password }
}).then(function(response) {
container.lookup('store:main').find('user', response.userId).then(function(user) {
resolve({ token: response.token, userId: response.userId, user: user });
});
container.lookup('store:main').find('user', response.userId).then(function(user) {
resolve({ token: response.token, userId: response.userId, user: user });
});
}, function(xhr, status, error) {
reject(xhr.responseJSON.errors);
reject(xhr.responseJSON.errors);
});
});
},
// invalidate: function(data) {
// return new Ember.RSVP.Promise();
// }
});
invalidate: function(data) {
return new Ember.RSVP.Promise(function() {
window.location = config.baseURL+'logout';
});
}
});

View File

@@ -1,11 +1,10 @@
import Base from 'simple-auth/authorizers/base';
export default Base.extend({
authorize: function(jqXHR, requestOptions) {
var token = this.get('session.token');
if (this.get('session.isAuthenticated') && !Ember.isEmpty(token)) {
jqXHR.setRequestHeader('Authorization', 'Token ' + token);
}
}
});
authorize: function(jqXHR, requestOptions) {
var token = this.get('session.token');
if (this.get('session.isAuthenticated') && !Ember.isEmpty(token)) {
jqXHR.setRequestHeader('Authorization', 'Token ' + token);
}
}
});

View File

@@ -1,17 +1,17 @@
import Ember from 'ember';
export default Ember.Controller.extend({
alerts: [],
alerts: [],
actions: {
alert: function(message) {
this.get('alerts').pushObject(message);
},
dismissAlert: function(message) {
this.get('alerts').removeObject(message);
},
clearAlerts: function() {
this.get('alerts').clear();
}
}
actions: {
alert: function(message) {
this.get('alerts').pushObject(message);
},
dismissAlert: function(message) {
this.get('alerts').removeObject(message);
},
clearAlerts: function() {
this.get('alerts').clear();
}
}
});

View File

@@ -54,6 +54,8 @@ export default Ember.Controller.extend({
}
}
// var results = Ember.RSVP.resolve(FLARUM_DATA.discussions);
return this.store.find('discussion', params).then(function(discussions) {
var results = Ember.A();
discussions.forEach(function(discussion) {

View File

@@ -4,31 +4,31 @@ import AuthenticationControllerMixin from 'simple-auth/mixins/authentication-con
import ModalController from 'flarum/mixins/modal-controller';
export default Ember.Controller.extend(ModalController, AuthenticationControllerMixin, {
authenticator: 'authenticator:flarum',
loading: false,
authenticator: 'authenticator:flarum',
loading: false,
actions: {
authenticate: function() {
actions: {
authenticate: function() {
var data = this.getProperties('identification', 'password');
var controller = this;
this.set('error', null);
this.set('loading', true);
return this._super(data).then(function() {
controller.send("sessionChanged");
controller.send("closeModal");
controller.send("sessionChanged");
controller.send("closeModal");
}, function(errors) {
switch(errors[0].code) {
case 'invalidLogin':
controller.set('error', 'Your login details are incorrect.');
break;
switch(errors[0].code) {
case 'invalidLogin':
controller.set('error', 'Your login details are incorrect.');
break;
default:
controller.set('error', 'Something went wrong. (Error code: '+errors[0].code+')');
}
controller.trigger('refocus');
default:
controller.set('error', 'Something went wrong. (Error code: '+errors[0].code+')');
}
controller.trigger('refocus');
}).finally(function() {
controller.set('loading', false);
controller.set('loading', false);
});
}
}
}
});

View File

@@ -3,6 +3,19 @@ import Ember from 'ember';
import ModalController from 'flarum/mixins/modal-controller';
export default Ember.Controller.extend(ModalController, {
emailProviderName: Ember.computed('welcomeUser.email', function() {
if (!this.get('welcomeUser.email')) { return; }
return this.get('welcomeUser.email').split('@')[1];
}),
emailProviderUrl: Ember.computed('emailProviderName', function() {
return 'http://'+this.get('emailProviderName');
}),
welcomeStyle: Ember.computed('welcomeUser.color', function() {
return 'background:'+this.get('welcomeUser.color');
}),
actions: {
submit: function() {
var data = this.getProperties('username', 'email', 'password');
@@ -12,15 +25,9 @@ export default Ember.Controller.extend(ModalController, {
var user = this.store.createRecord('user', data);
return user.save().then(function() {
controller.get('session').authenticate('authenticator:flarum', {
identification: data.email,
password: data.password
}).then(function() {
controller.send('closeModal');
controller.send('sessionChanged');
controller.set('loading', false);
});
return user.save().then(function(user) {
controller.set('welcomeUser', user);
controller.set('loading', false);
}, function(reason) {
controller.set('loading', false);
});

View File

@@ -1,9 +1,11 @@
import FlarumAuthorizer from 'flarum/authorizers/flarum';
import Config from 'flarum/config/environment';
export default {
name: 'authentication',
before: 'simple-auth',
initialize: function(container) {
container.register('authorizer:flarum', FlarumAuthorizer);
Config['simple-auth'] = {authorizer: 'authorizer:flarum'};
}
};

View File

@@ -0,0 +1,20 @@
import Ember from 'ember';
export default {
name: 'preload-data',
after: 'store',
initialize: function(container) {
var store = container.lookup('store:main');
if (!Ember.isEmpty(FLARUM_DATA)) {
store.pushPayload(FLARUM_DATA);
}
if (!Ember.isEmpty(FLARUM_SESSION)) {
FLARUM_SESSION.user = store.getById('user', FLARUM_SESSION.userId);
container.lookup('simple-auth-session:main').setProperties({
isAuthenticated: true,
authenticator: 'authenticator:flarum',
content: FLARUM_SESSION
});
}
}
};

View File

@@ -1,7 +1,15 @@
import Ember from 'ember';
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
import AlertMessage from 'flarum/components/ui/alert-message';
export default Ember.Route.extend(ApplicationRouteMixin, {
activate: function() {
if (!Ember.isEmpty(FLARUM_ALERT)) {
this.controllerFor('alerts').send('alert', AlertMessage.create(FLARUM_ALERT));
}
},
actions: {
login: function() {
this.controllerFor('login').set('error', null);
@@ -9,7 +17,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, {
},
signup: function() {
this.controllerFor('signup').set('error', null);
this.controllerFor('signup').set('error', null).set('welcomeUser', null);
this.send('showModal', 'signup');
},
@@ -33,7 +41,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, {
},
sessionChanged: function() {
this.refresh();
this.refresh();
}
}
});

View File

@@ -1,7 +1,7 @@
// This files is where our LESS journey begins.
// We begin by importing our own configuration variables, which are used all
// throughout the stylesheets. These pertain to
// throughout the stylesheets. These pertain to
// @import "config-default.less";
@import "config.less";
@@ -25,4 +25,5 @@
@import "@{flarum-base}index.less";
@import "@{flarum-base}discussion.less";
@import "@{flarum-base}login.less";
@import "@{flarum-base}login.less";
@import "@{flarum-base}signup.less";

View File

@@ -0,0 +1,23 @@
.signup-welcome {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: @border-radius-base - 1px;
padding: 60px;
text-align: center;
color: #fff;
& .avatar {
.avatar-size(64px);
.box-shadow(0 0 0 4px #fff);
}
& h3, & p {
margin-bottom: 20px;
}
& .btn-default {
background: fade(#000, 10%);
color: #fff;
}
}

View File

@@ -26,3 +26,15 @@
</form>
</div>
{{ui/loading-indicator classNameBindings=":modal-loading loading:active"}}
{{#if welcomeUser}}
<div {{bind-attr class=":signup-welcome :fade" style=welcomeStyle}}>
{{user-avatar welcomeUser}}
<h3>Welcome, {{welcomeUser.username}}!</h3>
{{#unless welcomeUser.isConfirmed}}
<p>We've sent a confirmation email to <strong>{{welcomeUser.email}}</strong>. If it doesn't arrive soon, check your spam folder.</p>
<p><a {{bind-attr href=emailProviderUrl}} class="btn btn-default">Go to {{emailProviderName}}</a></p>
{{/unless}}
</div>
{{/if}}

View File

@@ -7,5 +7,13 @@ export default Ember.View.extend(ModalView, {
templateName: 'signup',
didInsertElement: function() {
}
},
welcomeUserDidChange: Ember.observer('welcomeUser', function() {
if (this.get('welcomeUser')) {
Ember.run.scheduleOnce('afterRender', this, function() {
this.$('.signup-welcome').addClass('in');
});
}
})
});