Ghost/ghost/admin/app/controllers/setup/three.js
Kevin Ansfield e22eb668c4 💄 refactor setup screens to use ember-concurrency (#644)
refs TryGhost/Ghost#7865

💄 refactor signup to use ember-concurrency

refs https://github.com/TryGhost/Ghost/issues/7865
- moves authentication actions from `signup` route to controller
- refactors authentication and signup logic into EC tasks
- replaces use of `gh-spin-button` with `gh-task-button` in signup template

💄 refactor setup screens to use ember-concurrency

refs https://github.com/TryGhost/Ghost/issues/7865
- moves authentication actions from `setup/two` route to controller
- refactors authentication and setup logic into EC tasks
- replaces use of `gh-spin-button` with `gh-task-button`
- fixes some styling issues with the new SVG icons
- adds `app/styles/patterns/icons.css` back to contain per-icon overrides and animations (some SVGs use fills and others use strokes so we sometimes have conflicting styles)
2017-04-19 12:27:32 +02:00

246 lines
7.6 KiB
JavaScript

import Controller from 'ember-controller';
import RSVP from 'rsvp';
import computed, {alias} from 'ember-computed';
import {A as emberA} from 'ember-array/utils';
import injectService from 'ember-service/inject';
import injectController from 'ember-controller/inject';
import {htmlSafe} from 'ember-string';
import run from 'ember-runloop';
import DS from 'ember-data';
import {task, timeout} from 'ember-concurrency';
const {Errors} = DS;
export default Controller.extend({
notifications: injectService(),
two: injectController('setup/two'),
errors: Errors.create(),
hasValidated: emberA(),
users: '',
ownerEmail: alias('two.email'),
usersArray: computed('users', function () {
let errors = this.get('errors');
let users = this.get('users').split('\n').filter(function (email) {
return email.trim().length > 0;
});
// remove "no users to invite" error if we have users
if (users.uniq().length > 0 && errors.get('users.length') === 1) {
if (errors.get('users.firstObject').message.match(/no users/i)) {
errors.remove('users');
}
}
return users.uniq();
}),
validUsersArray: computed('usersArray', 'ownerEmail', function () {
let ownerEmail = this.get('ownerEmail');
return this.get('usersArray').filter(function (user) {
return validator.isEmail(user) && user !== ownerEmail;
});
}),
invalidUsersArray: computed('usersArray', 'ownerEmail', function () {
let ownerEmail = this.get('ownerEmail');
return this.get('usersArray').reject((user) => {
return validator.isEmail(user) || user === ownerEmail;
});
}),
validationResult: computed('invalidUsersArray', function () {
let errors = [];
this.get('invalidUsersArray').forEach((user) => {
errors.push({
user,
error: 'email'
});
});
if (errors.length === 0) {
// ensure we aren't highlighting fields when everything is fine
this.get('errors').clear();
return true;
} else {
return errors;
}
}),
validate() {
let errors = this.get('errors');
let validationResult = this.get('validationResult');
let property = 'users';
errors.clear();
// If property isn't in the `hasValidated` array, add it to mark that this field can show a validation result
this.get('hasValidated').addObject(property);
if (validationResult === true) {
return true;
}
validationResult.forEach((error) => {
// Only one error type here so far, but one day the errors might be more detailed
switch (error.error) {
case 'email':
errors.add(property, `${error.user} is not a valid email.`);
}
});
return false;
},
buttonText: computed('errors.users', 'validUsersArray', 'invalidUsersArray', function () {
let usersError = this.get('errors.users.firstObject.message');
let validNum = this.get('validUsersArray').length;
let invalidNum = this.get('invalidUsersArray').length;
let userCount;
if (usersError && usersError.match(/no users/i)) {
return usersError;
}
if (invalidNum > 0) {
userCount = invalidNum === 1 ? 'email address' : 'email addresses';
return `${invalidNum} invalid ${userCount}`;
}
if (validNum > 0) {
userCount = validNum === 1 ? 'user' : 'users';
userCount = `${validNum} ${userCount}`;
} else {
userCount = 'some users';
}
return `Invite ${userCount}`;
}),
buttonClass: computed('validationResult', 'usersArray.length', function () {
if (this.get('validationResult') === true && this.get('usersArray.length') > 0) {
return 'gh-btn-green';
} else {
return 'gh-btn-minor';
}
}),
authorRole: computed(function () {
return this.store.findAll('role', {reload: true}).then((roles) => {
return roles.findBy('name', 'Author');
});
}),
_transitionAfterSubmission() {
if (!this._hasTransitioned) {
this._hasTransitioned = true;
this.transitionToRoute('posts.index');
}
},
invite: task(function* () {
let users = this.get('usersArray');
if (this.validate() && users.length > 0) {
this._hasTransitioned = false;
this.get('_slowSubmissionTimeout').perform();
let authorRole = yield this.get('authorRole');
let invites = yield this._saveInvites(authorRole);
this.get('_slowSubmissionTimeout').cancelAll();
this._showNotifications(invites);
run.schedule('actions', this, function () {
this.send('loadServerNotifications');
this._transitionAfterSubmission();
});
} else if (users.length === 0) {
this.get('errors').add('users', 'No users to invite');
}
}).drop(),
_slowSubmissionTimeout: task(function* () {
yield timeout(4000);
this._transitionAfterSubmission();
}).drop(),
_saveInvites(authorRole) {
let users = this.get('usersArray');
return RSVP.Promise.all(
users.map((user) => {
let invite = this.store.createRecord('invite', {
email: user,
role: authorRole
});
return invite.save().then(() => {
return {
email: user,
success: invite.get('status') === 'sent'
};
}).catch(() => {
return {
email: user,
success: false
};
});
})
);
},
_showNotifications(invites) {
let notifications = this.get('notifications');
let erroredEmails = [];
let successCount = 0;
let invitationsString, message;
invites.forEach((invite) => {
if (invite.success) {
successCount++;
} else {
erroredEmails.push(invite.email);
}
});
if (erroredEmails.length > 0) {
invitationsString = erroredEmails.length > 1 ? ' invitations: ' : ' invitation: ';
message = `Failed to send ${erroredEmails.length} ${invitationsString}`;
message += erroredEmails.join(', ');
message += ". Please check your email configuration, see <a href=\'http://support.ghost.org/mail\' target=\'_blank\'>http://support.ghost.org/mail</a> for instructions";
message = htmlSafe(message);
notifications.showAlert(message, {type: 'error', delayed: successCount > 0, key: 'signup.send-invitations.failed'});
}
if (successCount > 0) {
// pluralize
invitationsString = successCount > 1 ? 'invitations' : 'invitation';
notifications.showAlert(`${successCount} ${invitationsString} sent!`, {type: 'success', delayed: true, key: 'signup.send-invitations.success'});
}
},
actions: {
validate() {
this.validate();
},
invite() {
this.get('invite').perform();
},
skipInvite() {
this.send('loadServerNotifications');
this.transitionToRoute('posts.index');
}
}
});