mirror of
https://github.com/flarum/framework.git
synced 2024-11-23 06:31:41 +08:00
Add ember-simple-auth, setup login
- Allow dropdown-buttons to render a partial
This commit is contained in:
parent
befb3d1929
commit
5cd87db5cf
37
framework/core/ember/app/authenticators/flarum.js
Normal file
37
framework/core/ember/app/authenticators/flarum.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import Base from 'simple-auth/authenticators/base';
|
||||
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',
|
||||
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 });
|
||||
});
|
||||
}, function(xhr, status, error) {
|
||||
reject(xhr.responseJSON.errors);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// invalidate: function(data) {
|
||||
// return new Ember.RSVP.Promise();
|
||||
// }
|
||||
});
|
11
framework/core/ember/app/authorizers/flarum.js
Normal file
11
framework/core/ember/app/authorizers/flarum.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,11 +1,32 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
// import NotificationMessage from '../models/notification-message';
|
||||
import AuthenticationControllerMixin from 'simple-auth/mixins/authentication-controller-mixin';
|
||||
|
||||
// export default Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, Ember.Evented, {
|
||||
export default Ember.Controller.extend(AuthenticationControllerMixin, {
|
||||
|
||||
// authenticatorFactory: 'authenticator:flarum'
|
||||
authenticator: 'authenticator:flarum',
|
||||
|
||||
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");
|
||||
}).catch(function(errors) {
|
||||
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+')');
|
||||
}
|
||||
}).finally(function() {
|
||||
controller.set('loading', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// });
|
||||
|
||||
export default Ember.Controller.extend();
|
||||
});
|
9
framework/core/ember/app/initializers/authentication.js
Normal file
9
framework/core/ember/app/initializers/authentication.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import FlarumAuthorizer from '../authorizers/flarum';
|
||||
|
||||
export default {
|
||||
name: 'authentication',
|
||||
before: 'simple-auth',
|
||||
initialize: function(container) {
|
||||
container.register('authorizer:flarum', FlarumAuthorizer);
|
||||
}
|
||||
};
|
|
@ -1,30 +1,27 @@
|
|||
import Ember from 'ember';
|
||||
// import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
|
||||
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
|
||||
|
||||
// export default Ember.Route.extend(ApplicationRouteMixin, {
|
||||
export default Ember.Route.extend(ApplicationRouteMixin, {
|
||||
|
||||
// actions: {
|
||||
actions: {
|
||||
login: function() {
|
||||
this.controllerFor('login').set('error', null);
|
||||
this.render('login', {
|
||||
into: 'application',
|
||||
outlet: 'modal'
|
||||
});
|
||||
},
|
||||
|
||||
// login: function() {
|
||||
// return this.render('login', {
|
||||
// into: 'application',
|
||||
// outlet: 'modal'
|
||||
// });
|
||||
// },
|
||||
closeModal: function() {
|
||||
this.disconnectOutlet({
|
||||
outlet: 'modal',
|
||||
parentView: 'application'
|
||||
});
|
||||
},
|
||||
|
||||
// doLogin: function() {
|
||||
// this.get('session').authenticate('authenticator:custom', {});
|
||||
// },
|
||||
sessionChanged: function() {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// closeModal: function() {
|
||||
// return this.disconnectOutlet({
|
||||
// outlet: 'modal',
|
||||
// parentView: 'application'
|
||||
// });
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
export default Ember.Route.extend();
|
||||
});
|
|
@ -18,7 +18,10 @@
|
|||
|
||||
// Finally, with our vendor CSS loaded, we can import Flarum-specific stuff.
|
||||
@import "@{flarum-base}components.less";
|
||||
@import "@{flarum-base}modals.less";
|
||||
@import "@{flarum-base}layout.less";
|
||||
@import "@{flarum-base}composer.less";
|
||||
|
||||
@import "@{flarum-base}index.less";
|
||||
@import "@{flarum-base}discussion.less";
|
||||
@import "@{flarum-base}discussion.less";
|
||||
@import "@{flarum-base}login.less";
|
32
framework/core/ember/app/styles/flarum/login.less
Normal file
32
framework/core/ember/app/styles/flarum/login.less
Normal file
|
@ -0,0 +1,32 @@
|
|||
.modal-login {
|
||||
& .form-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
.form-group {
|
||||
position: relative;
|
||||
}
|
||||
.form-alert {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-bottom: 12px;
|
||||
& .alert {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.alert-warning {
|
||||
background: #D83E3E;
|
||||
.box-shadow(0 2px 6px rgba(0, 0, 0, 0.3));
|
||||
color: #fff;
|
||||
padding: 12px 16px;
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
|
||||
.btn-user {
|
||||
& .avatar {
|
||||
margin: -2px 5px -2px -5px;
|
||||
.avatar-size(24px);
|
||||
}
|
||||
}
|
79
framework/core/ember/app/styles/flarum/modals.less
Normal file
79
framework/core/ember/app/styles/flarum/modals.less
Normal file
|
@ -0,0 +1,79 @@
|
|||
// ------------------------------------
|
||||
// Modals
|
||||
|
||||
.modal-backdrop {
|
||||
background-color: @fl-primary-color;
|
||||
&.in {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
.modal-dialog {
|
||||
margin: 120px auto;
|
||||
|
||||
& .close {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
.modal-content {
|
||||
border: 0;
|
||||
border-radius: @border-radius-base;
|
||||
.box-shadow(0 7px 15px rgba(0, 0, 0, 0.3));
|
||||
}
|
||||
.modal-sm {
|
||||
width: 375px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
text-align: center;
|
||||
border: 0;
|
||||
padding: 25px;
|
||||
|
||||
& h3 {
|
||||
font-size: 22px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.modal-body {
|
||||
background-color: @fl-secondary-color;
|
||||
padding: 25px;
|
||||
|
||||
& .form-control {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
border: 0;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: @fl-body-muted-color;
|
||||
}
|
||||
|
||||
.modal-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
border-radius: @border-radius-base;
|
||||
.transition(opacity 0.2s);
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.form-centered {
|
||||
text-align: center;
|
||||
|
||||
& .form-control, & .btn {
|
||||
width: 220px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
<a href="#" {{bind-attr class=":dropdown-toggle buttonClass"}} data-toggle="dropdown" {{action "buttonClick"}}>
|
||||
{{#if iconHtml}}
|
||||
{{{iconHtml}}}
|
||||
{{#if buttonPartial}}
|
||||
{{partial buttonPartial}}
|
||||
{{else}}
|
||||
{{fa-icon icon class="icon-glyph"}}
|
||||
<span class="label">{{label}}</span>
|
||||
{{fa-icon "caret-down" class="icon-caret"}}
|
||||
{{/if}}
|
||||
<span class="label">{{label}}</span>
|
||||
{{fa-icon "caret-down" class="icon-caret"}}
|
||||
</a>
|
||||
{{ui/controls/item-list items=items class=dropdownMenuClass}}
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-dialog modal-sm modal-login">
|
||||
<div class="modal-content">
|
||||
<form {{action 'authenticate' on='submit'}}>
|
||||
<button class="close btn btn-icon btn-link" {{action "close" target="view"}}>{{fa-icon "times"}}</button>
|
||||
<form {{action "authenticate" on="submit"}}>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" {{action close target="view"}}>×</button>
|
||||
<h3 style="margin:0">Log In</h3>
|
||||
<h3>Log In</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
{{input value=identification type="text" class="form-control" placeholder="Username or Email"}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{input value=password type="password" class="form-control" placeholder="Password"}}
|
||||
</div>
|
||||
<div class="checkbox" style="margin:0">
|
||||
<label>
|
||||
{{input checked=remember type="checkbox"}} Remember me
|
||||
</label>
|
||||
<div class="form-centered">
|
||||
<div class="form-group">
|
||||
{{#if error}}
|
||||
<div class="form-alert">
|
||||
<div class="alert alert-warning">{{error}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{input value=identification name="email" type="text" class="form-control" placeholder="Username or Email" disabled=loading}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{{input value=password name="password" type="password" class="form-control" placeholder="Password" disabled=loading}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-block" {{bind-attr disabled=loading}}>Log In</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" style="margin:0">
|
||||
<a href="#" class="btn btn-default" {{action close target="view"}}>Close</a>
|
||||
{{input class="btn btn-primary" type="submit" value="Log In"}}
|
||||
<div class="modal-footer">
|
||||
<p class="forgot-password-link"><a href="#">Forgot password?</a></p>
|
||||
<p class="sign-up-link">Don't have an account? <a href="#">Sign Up</a></p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{{ui/controls/loading-indicator classNameBindings=":modal-loading loading:active"}}
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
{{user-avatar user}}
|
||||
<span class="label">{{label}}</span>
|
|
@ -3,6 +3,8 @@ import Ember from 'ember';
|
|||
import ActionButton from '../components/ui/controls/action-button';
|
||||
import SearchInput from '../components/ui/controls/search-input';
|
||||
import DropdownSelect from '../components/ui/controls/dropdown-select';
|
||||
import DropdownButton from '../components/ui/controls/dropdown-button';
|
||||
import SeparatorItem from '../components/ui/items/separator-item';
|
||||
import TaggedArray from '../utils/tagged-array';
|
||||
|
||||
var $ = Ember.$;
|
||||
|
@ -14,10 +16,7 @@ export default Ember.View.extend({
|
|||
}.property('controller.forumTitle'),
|
||||
|
||||
didInsertElement: function() {
|
||||
// Create and populate an array of items to be rendered in the header.
|
||||
this.set('headerPrimaryItems', TaggedArray.create());
|
||||
this.set('headerSecondaryItems', TaggedArray.create());
|
||||
this.trigger('populateHeader', this.get('headerPrimaryItems'), this.get('headerSecondaryItems'));
|
||||
|
||||
|
||||
// Create and populate an array of items to be rendered in the footer.
|
||||
this.set('footerPrimaryItems', TaggedArray.create());
|
||||
|
@ -36,6 +35,13 @@ export default Ember.View.extend({
|
|||
}).resize();
|
||||
},
|
||||
|
||||
switchHeader: function() {
|
||||
// Create and populate an array of items to be rendered in the header.
|
||||
this.set('headerPrimaryItems', TaggedArray.create());
|
||||
this.set('headerSecondaryItems', TaggedArray.create());
|
||||
this.trigger('populateHeader', this.get('headerPrimaryItems'), this.get('headerSecondaryItems'));
|
||||
}.observes('controller.session.user'),
|
||||
|
||||
populateHeaderDefault: function(primary, secondary) {
|
||||
var controller = this.get('controller');
|
||||
|
||||
|
@ -50,17 +56,64 @@ export default Ember.View.extend({
|
|||
});
|
||||
secondary.pushObjectWithTag(search, 'search');
|
||||
|
||||
var signUp = ActionButton.create({
|
||||
label: 'Sign Up',
|
||||
className: 'btn btn-link'
|
||||
});
|
||||
secondary.pushObjectWithTag(signUp, 'signUp');
|
||||
if (this.get('controller.session.isAuthenticated')) {
|
||||
var userItems = TaggedArray.create();
|
||||
|
||||
var logIn = ActionButton.create({
|
||||
label: 'Log In',
|
||||
className: 'btn btn-link'
|
||||
});
|
||||
secondary.pushObjectWithTag(logIn, 'logIn');
|
||||
var profile = ActionButton.create({
|
||||
label: 'Profile',
|
||||
icon: 'user'
|
||||
});
|
||||
userItems.pushObjectWithTag(profile, 'profile');
|
||||
|
||||
var settings = ActionButton.create({
|
||||
label: 'Settings',
|
||||
icon: 'cog'
|
||||
});
|
||||
userItems.pushObjectWithTag(settings, 'settings');
|
||||
|
||||
userItems.pushObject(SeparatorItem.create());
|
||||
|
||||
var rememberMe = ActionButton.create({
|
||||
label: 'Remember Me',
|
||||
icon: 'square-o'
|
||||
});
|
||||
userItems.pushObjectWithTag(rememberMe, 'rememberMe');
|
||||
|
||||
var logOut = ActionButton.create({
|
||||
label: 'Log Out',
|
||||
icon: 'sign-out',
|
||||
action: function() {
|
||||
controller.send('invalidateSession');
|
||||
}
|
||||
});
|
||||
userItems.pushObjectWithTag(logOut, 'logOut');
|
||||
|
||||
var userDropdown = DropdownButton.extend({
|
||||
label: Ember.computed.alias('user.username'),
|
||||
buttonClass: 'btn btn-default btn-naked btn-rounded btn-user',
|
||||
buttonPartial: 'partials/user-button',
|
||||
menuClass: 'pull-right'
|
||||
});
|
||||
secondary.pushObjectWithTag(userDropdown.create({
|
||||
items: userItems,
|
||||
user: this.get('controller.session.user')
|
||||
}), 'user');
|
||||
} else {
|
||||
var signUp = ActionButton.create({
|
||||
label: 'Sign Up',
|
||||
className: 'btn btn-link'
|
||||
});
|
||||
secondary.pushObjectWithTag(signUp, 'signUp');
|
||||
|
||||
var logIn = ActionButton.create({
|
||||
label: 'Log In',
|
||||
className: 'btn btn-link',
|
||||
action: function() {
|
||||
controller.send('login');
|
||||
}
|
||||
});
|
||||
secondary.pushObjectWithTag(logIn, 'logIn');
|
||||
}
|
||||
}.on('populateHeader'),
|
||||
|
||||
populateFooterDefault: function(primary, secondary) {
|
||||
|
|
|
@ -8,11 +8,20 @@ export default Ember.View.extend({
|
|||
var self = this;
|
||||
this.$().modal('show').on('hidden.bs.modal', function() {
|
||||
self.get('controller').send('closeModal');
|
||||
}).on('shown.bs.modal', function() {
|
||||
$(this).find('input:first').select();
|
||||
});
|
||||
|
||||
this.get('controller.session').on('sessionAuthenticationSucceeded', this, this.hide);
|
||||
},
|
||||
|
||||
refocus: function() {
|
||||
var view = this;
|
||||
Ember.run.scheduleOnce('afterRender', function() {
|
||||
view.$('input[name=password]').select();
|
||||
});
|
||||
}.observes('controller.loading'),
|
||||
|
||||
willDestroyElement: function() {
|
||||
this.get('controller.session').off('sessionAuthenticationSucceeded', this, this.hide);
|
||||
},
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
"font-awesome": "~4",
|
||||
"spin.js": "~2.0.1",
|
||||
"pace": "~0.7.1",
|
||||
"moment": "~2.8.4"
|
||||
"moment": "~2.8.4",
|
||||
"ember-simple-auth": "0.7.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@ module.exports = function(environment) {
|
|||
}
|
||||
};
|
||||
|
||||
ENV['simple-auth'] = {
|
||||
authorizer: 'authorizer:flarum'
|
||||
};
|
||||
|
||||
if (environment === 'development') {
|
||||
// ENV.APP.LOG_RESOLVER = true;
|
||||
// ENV.APP.LOG_ACTIVE_GENERATION = true;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"ember-cli-inject-live-reload": "^1.3.0",
|
||||
"ember-cli-less": "^1.0.5",
|
||||
"ember-cli-qunit": "0.1.2",
|
||||
"ember-cli-simple-auth": "^0.7.2",
|
||||
"ember-data": "1.0.0-beta.14",
|
||||
"ember-dynamic-component": "0.0.4",
|
||||
"ember-export-application-global": "^1.0.0",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<meta name="flarum/config/environment" content="%7B%22modulePrefix%22%3A%22flarum%22%2C%22environment%22%3A%22development%22%2C%22baseURL%22%3A%22/%22%2C%22apiURL%22%3A%22/api%22%2C%22locationType%22%3A%22hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%7D%2C%22APP%22%3A%7B%7D%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy-Report-Only%22%2C%22contentSecurityPolicy%22%3A%7B%22default-src%22%3A%22%27none%27%22%2C%22script-src%22%3A%22%27self%27%20%27unsafe-eval%27%22%2C%22font-src%22%3A%22%27self%27%22%2C%22connect-src%22%3A%22%27self%27%22%2C%22img-src%22%3A%22%27self%27%22%2C%22style-src%22%3A%22%27self%27%22%2C%22media-src%22%3A%22%27self%27%22%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
|
||||
<meta name="flarum/config/environment" content="%7B%22modulePrefix%22%3A%22flarum%22%2C%22environment%22%3A%22development%22%2C%22baseURL%22%3A%22/%22%2C%22apiURL%22%3A%22/api%22%2C%22locationType%22%3A%22hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%7D%2C%22APP%22%3A%7B%7D%2C%22simple-auth%22%3A%7B%22authorizer%22%3A%22authorizer%3Aflarum%22%7D%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy-Report-Only%22%2C%22contentSecurityPolicy%22%3A%7B%22default-src%22%3A%22%27none%27%22%2C%22script-src%22%3A%22%27self%27%20%27unsafe-eval%27%22%2C%22font-src%22%3A%22%27self%27%22%2C%22connect-src%22%3A%22%27self%27%22%2C%22img-src%22%3A%22%27self%27%22%2C%22style-src%22%3A%22%27self%27%22%2C%22media-src%22%3A%22%27self%27%22%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
|
||||
|
||||
<base href="/">
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user