mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
FEATURE: Show user fields when the user is signing up
This commit is contained in:
@ -13,10 +13,12 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
|||||||
save: function() {
|
save: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.commitBuffer();
|
var attrs = this.get('buffered').getProperties('name', 'field_type', 'editable');
|
||||||
this.get('model').save().then(function(res) {
|
|
||||||
|
this.get('model').save(attrs).then(function(res) {
|
||||||
self.set('model.id', res.user_field.id);
|
self.set('model.id', res.user_field.id);
|
||||||
self.set('editing', false);
|
self.set('editing', false);
|
||||||
|
self.commitBuffer();
|
||||||
}).catch(function() {
|
}).catch(function() {
|
||||||
bootbox.alert(I18n.t('generic_error'));
|
bootbox.alert(I18n.t('generic_error'));
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,10 @@ import UserField from 'admin/models/user-field';
|
|||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
export default Ember.ArrayController.extend({
|
||||||
fieldTypes: null,
|
fieldTypes: null,
|
||||||
|
|
||||||
createDisabled: Em.computed.gte('model.length', 3),
|
createDisabled: Em.computed.gte('model.length', 3),
|
||||||
|
userFieldsName: function() {
|
||||||
|
return I18n.t('admin.user_fields.name');
|
||||||
|
}.property(),
|
||||||
|
|
||||||
_performDestroy: function(f, model) {
|
_performDestroy: function(f, model) {
|
||||||
return f.destroy().then(function() {
|
return f.destroy().then(function() {
|
||||||
@ -13,10 +15,7 @@ export default Ember.ArrayController.extend({
|
|||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
createField: function() {
|
createField: function() {
|
||||||
this.pushObject(UserField.create({
|
this.pushObject(UserField.create({ field_type: 'text' }));
|
||||||
field_type: 'text',
|
|
||||||
name: I18n.t('admin.user_fields.untitled')
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function(f) {
|
destroy: function(f) {
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||||
|
|
||||||
/**
|
|
||||||
A controller related to viewing a user in the admin section
|
|
||||||
|
|
||||||
@class AdminUserIndexController
|
|
||||||
@extends ObjectController
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
export default ObjectController.extend(CanCheckEmails, {
|
export default ObjectController.extend(CanCheckEmails, {
|
||||||
editingTitle: false,
|
editingTitle: false,
|
||||||
originalPrimaryGroupId: null,
|
originalPrimaryGroupId: null,
|
||||||
@ -23,6 +15,19 @@ export default ObjectController.extend(CanCheckEmails, {
|
|||||||
return (!g.automatic && g.visible);
|
return (!g.automatic && g.visible);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
userFields: function() {
|
||||||
|
var siteUserFields = this.site.get('user_fields'),
|
||||||
|
userFields = this.get('user_fields');
|
||||||
|
|
||||||
|
if (!Ember.empty(siteUserFields)) {
|
||||||
|
return siteUserFields.map(function(uf) {
|
||||||
|
var value = userFields ? userFields[uf.get('id').toString()] : null;
|
||||||
|
return {name: uf.get('name'), value: value};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}.property('user_fields.@each'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
toggleTitleEdit: function() {
|
toggleTitleEdit: function() {
|
||||||
this.toggleProperty('editingTitle');
|
this.toggleProperty('editingTitle');
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
import ObjectController from 'discourse/controllers/object';
|
import ObjectController from 'discourse/controllers/object';
|
||||||
|
|
||||||
/**
|
|
||||||
The top-level controller for user pages in admin.
|
|
||||||
Ember assertion says that this class needs to be defined even if it's empty.
|
|
||||||
|
|
||||||
@class AdminUserController
|
|
||||||
@extends ObjectController
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
export default ObjectController.extend();
|
export default ObjectController.extend();
|
||||||
|
@ -17,17 +17,17 @@ var UserField = Ember.Object.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
save: function() {
|
save: function(attrs) {
|
||||||
var id = this.get('id');
|
var id = this.get('id');
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return Discourse.ajax("/admin/customize/user_fields", {
|
return Discourse.ajax("/admin/customize/user_fields", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { user_field: this.getProperties('name', 'field_type') }
|
data: { user_field: attrs }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Discourse.ajax("/admin/customize/user_fields/" + id, {
|
return Discourse.ajax("/admin/customize/user_fields/" + id, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { user_field: this.getProperties('name', 'field_type') }
|
data: { user_field: attrs }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.colors.title}}{{/link-to}}</li>
|
<li>{{#link-to 'adminCustomize.colors'}}{{i18n admin.customize.colors.title}}{{/link-to}}</li>
|
||||||
<li>{{#link-to 'adminCustomize.css_html'}}{{i18n admin.customize.css_html.title}}{{/link-to}}</li>
|
<li>{{#link-to 'adminCustomize.css_html'}}{{i18n admin.customize.css_html.title}}{{/link-to}}</li>
|
||||||
<li>{{#link-to 'adminSiteText'}}{{i18n admin.site_text.title}}{{/link-to}}</li>
|
<li>{{#link-to 'adminSiteText'}}{{i18n admin.site_text.title}}{{/link-to}}</li>
|
||||||
{{#if userFieldFeatureComplete}}
|
|
||||||
<li>{{#link-to 'adminUserFields'}}{{i18n admin.user_fields.title}}{{/link-to}}</li>
|
<li>{{#link-to 'adminUserFields'}}{{i18n admin.user_fields.title}}{{/link-to}}</li>
|
||||||
{{/if}}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,13 +7,14 @@
|
|||||||
{{#each f in model itemController="admin-user-field-item" itemView="admin-user-field-item"}}
|
{{#each f in model itemController="admin-user-field-item" itemView="admin-user-field-item"}}
|
||||||
{{#if f.editing}}
|
{{#if f.editing}}
|
||||||
<div class='form-element'>
|
<div class='form-element'>
|
||||||
<label>{{i18n admin.user_fields.name}}
|
{{input value=f.buffered.name class="user-field-name" placeholder=userFieldsName}}
|
||||||
{{input value=f.buffered.name class="user-field-name"}}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element'>
|
<div class='form-element'>
|
||||||
<label>{{i18n admin.user_fields.type}}
|
|
||||||
{{combo-box content=fieldTypes valueAttribute="id" value=f.buffered.field_type}}
|
{{combo-box content=fieldTypes valueAttribute="id" value=f.buffered.field_type}}
|
||||||
|
</div>
|
||||||
|
<div class='form-element'>
|
||||||
|
<label>
|
||||||
|
{{input type="checkbox" checked=f.buffered.editable}} {{i18n admin.user_fields.editable.title}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element controls'>
|
<div class='form-element controls'>
|
||||||
@ -21,11 +22,14 @@
|
|||||||
<button {{action "cancel"}} class='btn btn-danger'>{{fa-icon 'times'}} {{i18n admin.user_fields.cancel}}</button>
|
<button {{action "cancel"}} class='btn btn-danger'>{{fa-icon 'times'}} {{i18n admin.user_fields.cancel}}</button>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
<div class='form-display'>{{f.name}}</div>
|
||||||
|
<div class='form-display'>{{f.fieldName}}</div>
|
||||||
<div class='form-display'>
|
<div class='form-display'>
|
||||||
{{f.name}}
|
{{#if f.editable}}
|
||||||
</div>
|
{{i18n admin.user_fields.editable.enabled}}
|
||||||
<div class='form-display'>
|
{{else}}
|
||||||
{{f.fieldName}}
|
{{i18n admin.user_fields.editable.disabled}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element controls'>
|
<div class='form-element controls'>
|
||||||
<button {{action "edit"}}class='btn btn-default'>{{fa-icon 'pencil'}} {{i18n admin.user_fields.edit}}</button>
|
<button {{action "edit"}}class='btn btn-default'>{{fa-icon 'pencil'}} {{i18n admin.user_fields.edit}}</button>
|
||||||
|
@ -137,9 +137,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{#if userFields}}
|
||||||
|
<section class='details'>
|
||||||
|
{{#each userFields}}
|
||||||
|
<div class='display-row'>
|
||||||
|
<div class='field'>{{name}}</div>
|
||||||
|
<div class='value'>
|
||||||
|
{{#if value}}
|
||||||
|
{{value}}
|
||||||
|
{{else}}
|
||||||
|
—
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</section>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
<section class='details'>
|
<section class='details'>
|
||||||
<h1>{{i18n admin.user.permissions}}</h1>
|
<h1>{{i18n admin.user.permissions}}</h1>
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
export default Ember.Component.extend({
|
||||||
|
classNameBindings: [':user-field'],
|
||||||
|
layoutName: function() {
|
||||||
|
return "components/user-fields/" + this.get('field.field_type');
|
||||||
|
}.property('field.field_type')
|
||||||
|
});
|
@ -15,6 +15,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
rejectedPasswords: Em.A([]),
|
rejectedPasswords: Em.A([]),
|
||||||
prefilledUsername: null,
|
prefilledUsername: null,
|
||||||
tosAccepted: false,
|
tosAccepted: false,
|
||||||
|
userFields: null,
|
||||||
|
|
||||||
hasAuthOptions: Em.computed.notEmpty('authOptions'),
|
hasAuthOptions: Em.computed.notEmpty('authOptions'),
|
||||||
canCreateLocal: Discourse.computed.setting('enable_local_logins'),
|
canCreateLocal: Discourse.computed.setting('enable_local_logins'),
|
||||||
@ -22,6 +23,8 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
maxUsernameLength: Discourse.computed.setting('max_username_length'),
|
maxUsernameLength: Discourse.computed.setting('max_username_length'),
|
||||||
|
|
||||||
resetForm: function() {
|
resetForm: function() {
|
||||||
|
|
||||||
|
// We wrap the fields in a structure so we can assign a value
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
accountName: '',
|
accountName: '',
|
||||||
accountEmail: '',
|
accountEmail: '',
|
||||||
@ -31,10 +34,11 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
globalNicknameExists: false,
|
globalNicknameExists: false,
|
||||||
complete: false,
|
complete: false,
|
||||||
formSubmitted: false,
|
formSubmitted: false,
|
||||||
rejectedEmails: Em.A([]),
|
rejectedEmails: [],
|
||||||
rejectedPasswords: Em.A([]),
|
rejectedPasswords: [],
|
||||||
prefilledUsername: null
|
prefilledUsername: null,
|
||||||
});
|
});
|
||||||
|
this._createUserFields();
|
||||||
},
|
},
|
||||||
|
|
||||||
submitDisabled: function() {
|
submitDisabled: function() {
|
||||||
@ -47,8 +51,18 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
if (this.get('emailValidation.failed')) return true;
|
if (this.get('emailValidation.failed')) return true;
|
||||||
if (this.get('usernameValidation.failed')) return true;
|
if (this.get('usernameValidation.failed')) return true;
|
||||||
if (this.get('passwordValidation.failed')) return true;
|
if (this.get('passwordValidation.failed')) return true;
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
var userFields = this.get('userFields');
|
||||||
|
if (!Ember.empty(userFields)) {
|
||||||
|
var anyEmpty = userFields.any(function(uf) {
|
||||||
|
var val = uf.get('value');
|
||||||
|
return !val || Ember.empty(val);
|
||||||
|
});
|
||||||
|
if (anyEmpty) { return true; }
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted', 'tosAccepted'),
|
}.property('passwordRequired', 'nameValidation.failed', 'emailValidation.failed', 'usernameValidation.failed', 'passwordValidation.failed', 'formSubmitted', 'tosAccepted', 'userFields.@each.value'),
|
||||||
|
|
||||||
passwordRequired: function() {
|
passwordRequired: function() {
|
||||||
return this.blank('authOptions.auth_provider');
|
return this.blank('authOptions.auth_provider');
|
||||||
@ -337,20 +351,25 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
createAccount: function() {
|
createAccount: function() {
|
||||||
var self = this;
|
var self = this,
|
||||||
|
attrs = this.getProperties('accountName', 'accountEmail', 'accountPassword', 'accountUsername', 'accountPasswordConfirm', 'accountChallenge'),
|
||||||
|
userFields = this.get('userFields');
|
||||||
|
|
||||||
|
// Add the userfields to the data
|
||||||
|
if (!Em.empty(userFields)) {
|
||||||
|
attrs.userFields = {};
|
||||||
|
userFields.forEach(function(f) {
|
||||||
|
attrs.userFields[f.get('field.id')] = f.get('value');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.set('formSubmitted', true);
|
this.set('formSubmitted', true);
|
||||||
var name = this.get('accountName');
|
return Discourse.User.createAccount(attrs).then(function(result) {
|
||||||
var email = this.get('accountEmail');
|
|
||||||
var password = this.get('accountPassword');
|
|
||||||
var username = this.get('accountUsername');
|
|
||||||
var passwordConfirm = this.get('accountPasswordConfirm');
|
|
||||||
var challenge = this.get('accountChallenge');
|
|
||||||
return Discourse.User.createAccount(name, email, password, username, passwordConfirm, challenge).then(function(result) {
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Trigger the browser's password manager using the hidden static login form:
|
// Trigger the browser's password manager using the hidden static login form:
|
||||||
var $hidden_login_form = $('#hidden-login-form');
|
var $hidden_login_form = $('#hidden-login-form');
|
||||||
$hidden_login_form.find('input[name=username]').val(self.get('accountName'));
|
$hidden_login_form.find('input[name=username]').val(attrs.accountName);
|
||||||
$hidden_login_form.find('input[name=password]').val(self.get('accountPassword'));
|
$hidden_login_form.find('input[name=password]').val(attrs.accountPassword);
|
||||||
$hidden_login_form.find('input[name=redirect]').val(Discourse.getURL('/users/account-created'));
|
$hidden_login_form.find('input[name=redirect]').val(Discourse.getURL('/users/account-created'));
|
||||||
$hidden_login_form.submit();
|
$hidden_login_form.submit();
|
||||||
} else {
|
} else {
|
||||||
@ -359,7 +378,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
self.get('rejectedEmails').pushObject(result.values.email);
|
self.get('rejectedEmails').pushObject(result.values.email);
|
||||||
}
|
}
|
||||||
if (result.errors && result.errors.password && result.errors.password.length > 0) {
|
if (result.errors && result.errors.password && result.errors.password.length > 0) {
|
||||||
self.get('rejectedPasswords').pushObject(password);
|
self.get('rejectedPasswords').pushObject(attrs.accountPassword);
|
||||||
}
|
}
|
||||||
self.set('formSubmitted', false);
|
self.set('formSubmitted', false);
|
||||||
}
|
}
|
||||||
@ -371,5 +390,21 @@ export default DiscourseController.extend(ModalFunctionality, {
|
|||||||
return self.flash(I18n.t('create_account.failed'), 'error');
|
return self.flash(I18n.t('create_account.failed'), 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
_createUserFields: function() {
|
||||||
|
if (!this.site) { return; }
|
||||||
|
|
||||||
|
var userFields = this.site.get('user_fields');
|
||||||
|
if (userFields) {
|
||||||
|
userFields = userFields.map(function(f) {
|
||||||
|
return Ember.Object.create({
|
||||||
|
value: null,
|
||||||
|
field: f
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.set('userFields', userFields);
|
||||||
|
}.on('init')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -18,6 +18,17 @@ export default ObjectController.extend(CanCheckEmails, {
|
|||||||
|
|
||||||
newNameInput: null,
|
newNameInput: null,
|
||||||
|
|
||||||
|
userFields: function() {
|
||||||
|
var siteUserFields = this.site.get('user_fields');
|
||||||
|
if (!Ember.empty(siteUserFields)) {
|
||||||
|
var userFields = this.get('user_fields');
|
||||||
|
return siteUserFields.filterProperty('editable', true).map(function(uf) {
|
||||||
|
var val = userFields ? userFields[uf.get('id').toString()] : null;
|
||||||
|
return Ember.Object.create({value: val, field: uf});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.property('user_fields.@each.value'),
|
||||||
|
|
||||||
cannotDeleteAccount: Em.computed.not('can_delete_account'),
|
cannotDeleteAccount: Em.computed.not('can_delete_account'),
|
||||||
deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'),
|
deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'),
|
||||||
|
|
||||||
@ -70,8 +81,20 @@ export default ObjectController.extend(CanCheckEmails, {
|
|||||||
var self = this;
|
var self = this;
|
||||||
this.setProperties({ saving: true, saved: false });
|
this.setProperties({ saving: true, saved: false });
|
||||||
|
|
||||||
|
var model = this.get('model'),
|
||||||
|
userFields = this.get('userFields');
|
||||||
|
|
||||||
|
// Update the user fields
|
||||||
|
if (!Em.empty(userFields)) {
|
||||||
|
var modelFields = model.get('user_fields');
|
||||||
|
if (!Em.empty(modelFields)) {
|
||||||
|
userFields.forEach(function(uf) {
|
||||||
|
modelFields[uf.get('field.id').toString()] = uf.get('value');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cook the bio for preview
|
// Cook the bio for preview
|
||||||
var model = this.get('model');
|
|
||||||
model.set('name', this.get('newNameInput'));
|
model.set('name', this.get('newNameInput'));
|
||||||
return model.save().then(function() {
|
return model.save().then(function() {
|
||||||
// model was saved
|
// model was saved
|
||||||
|
@ -133,6 +133,12 @@ Discourse.Site.reopenClass(Discourse.Singleton, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.user_fields) {
|
||||||
|
result.user_fields = result.user_fields.map(function(uf) {
|
||||||
|
return Ember.Object.create(uf);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -188,8 +188,8 @@ Discourse.User = Discourse.Model.extend({
|
|||||||
@returns {Promise} the result of the operation
|
@returns {Promise} the result of the operation
|
||||||
**/
|
**/
|
||||||
save: function() {
|
save: function() {
|
||||||
var user = this;
|
var self = this,
|
||||||
var data = this.getProperties('auto_track_topics_after_msecs',
|
data = this.getProperties('auto_track_topics_after_msecs',
|
||||||
'bio_raw',
|
'bio_raw',
|
||||||
'website',
|
'website',
|
||||||
'location',
|
'location',
|
||||||
@ -206,10 +206,11 @@ Discourse.User = Discourse.Model.extend({
|
|||||||
'mailing_list_mode',
|
'mailing_list_mode',
|
||||||
'enable_quoting',
|
'enable_quoting',
|
||||||
'disable_jump_reply',
|
'disable_jump_reply',
|
||||||
'custom_fields');
|
'custom_fields',
|
||||||
|
'user_fields');
|
||||||
|
|
||||||
_.each(['muted','watched','tracked'], function(s){
|
['muted','watched','tracked'].forEach(function(s){
|
||||||
var cats = user.get(s + 'Categories').map(function(c){ return c.get('id')});
|
var cats = self.get(s + 'Categories').map(function(c){ return c.get('id')});
|
||||||
// HACK: denote lack of categories
|
// HACK: denote lack of categories
|
||||||
if(cats.length === 0) { cats = [-1]; }
|
if(cats.length === 0) { cats = [-1]; }
|
||||||
data[s + '_category_ids'] = cats;
|
data[s + '_category_ids'] = cats;
|
||||||
@ -223,13 +224,10 @@ Discourse.User = Discourse.Model.extend({
|
|||||||
data: data,
|
data: data,
|
||||||
type: 'PUT'
|
type: 'PUT'
|
||||||
}).then(function(data) {
|
}).then(function(data) {
|
||||||
user.set('bio_excerpt',data.user.bio_excerpt);
|
self.set('bio_excerpt',data.user.bio_excerpt);
|
||||||
|
|
||||||
_.each([
|
var userProps = self.getProperties('enable_quoting', 'external_links_in_new_tab', 'dynamic_favicon');
|
||||||
'enable_quoting', 'external_links_in_new_tab', 'dynamic_favicon'
|
Discourse.User.current().setProperties(userProps);
|
||||||
], function(preference) {
|
|
||||||
Discourse.User.current().set(preference, user.get(preference));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -542,26 +540,18 @@ Discourse.User.reopenClass(Discourse.Singleton, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a new account over POST
|
Creates a new account
|
||||||
|
|
||||||
@method createAccount
|
|
||||||
@param {String} name This user's name
|
|
||||||
@param {String} email This user's email
|
|
||||||
@param {String} password This user's password
|
|
||||||
@param {String} username This user's username
|
|
||||||
@param {String} passwordConfirm This user's confirmed password
|
|
||||||
@param {String} challenge
|
|
||||||
@returns Result of ajax call
|
|
||||||
**/
|
**/
|
||||||
createAccount: function(name, email, password, username, passwordConfirm, challenge) {
|
createAccount: function(attrs) {
|
||||||
return Discourse.ajax("/users", {
|
return Discourse.ajax("/users", {
|
||||||
data: {
|
data: {
|
||||||
name: name,
|
name: attrs.accountName,
|
||||||
email: email,
|
email: attrs.accountEmail,
|
||||||
password: password,
|
password: attrs.accountPassword,
|
||||||
username: username,
|
username: attrs.accountUsername,
|
||||||
password_confirmation: passwordConfirm,
|
password_confirmation: attrs.accountPasswordConfirm,
|
||||||
challenge: challenge
|
challenge: attrs.accountChallenge,
|
||||||
|
user_fields: attrs.userFields
|
||||||
},
|
},
|
||||||
type: 'POST'
|
type: 'POST'
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
<label>
|
||||||
|
{{input checked=value type="checkbox"}} {{field.name}}
|
||||||
|
</label>
|
@ -0,0 +1,4 @@
|
|||||||
|
<label>
|
||||||
|
{{field.name}}
|
||||||
|
{{input value=value}}
|
||||||
|
</label>
|
@ -70,6 +70,17 @@
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
{{#if userFields}}
|
||||||
|
<div class='user-fields'>
|
||||||
|
<h3>{{i18n create_account.required_information}}</h3>
|
||||||
|
|
||||||
|
{{#each userFields}}
|
||||||
|
{{user-field field=field value=value}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
@ -178,6 +178,11 @@
|
|||||||
{{#unless editHistoryVisible}}
|
{{#unless editHistoryVisible}}
|
||||||
{{preference-checkbox labelKey="user.edit_history_public" checked=edit_history_public}}
|
{{preference-checkbox labelKey="user.edit_history_public" checked=edit_history_public}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
|
{{#each userFields}}
|
||||||
|
{{user-field field=field value=value}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
{{plugin-outlet "user_custom_preferences"}}
|
{{plugin-outlet "user_custom_preferences"}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export default Discourse.ModalBodyView.extend({
|
export default Discourse.ModalBodyView.extend({
|
||||||
templateName: 'modal/create_account',
|
templateName: 'modal/create-account',
|
||||||
title: I18n.t('create_account.title'),
|
title: I18n.t('create_account.title'),
|
||||||
classNames: ['create-account'],
|
classNames: ['create-account'],
|
||||||
|
|
||||||
|
@ -1331,21 +1331,14 @@ tr.not-activated {
|
|||||||
border-bottom: 1px solid scale-color-diff();
|
border-bottom: 1px solid scale-color-diff();
|
||||||
|
|
||||||
.form-display {
|
.form-display {
|
||||||
width: 35%;
|
width: 25%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-element {
|
.form-element {
|
||||||
float: left;
|
float: left;
|
||||||
width: 35%;
|
width: 25%;
|
||||||
margin-right: 10px;
|
|
||||||
label {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
input, div.combobox {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
|
@ -11,3 +11,28 @@
|
|||||||
.discourse-touch .caps-lock-warning {
|
.discourse-touch .caps-lock-warning {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.user-fields {
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
line-height: 1.5em;
|
||||||
|
color: scale-color($primary, $lightness: 20%);
|
||||||
|
border-bottom: 1px solid scale-color($primary, $lightness: 50%);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-field {
|
||||||
|
label: {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
input[type=text] {
|
||||||
|
width: 80%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
input[type=checkbox] {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -63,3 +63,4 @@
|
|||||||
margin: 5px 10px 5px 0;
|
margin: 5px 10px 5px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,4 +426,13 @@
|
|||||||
.suspensions {
|
.suspensions {
|
||||||
background-color: #c22020;
|
background-color: #c22020;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-field {
|
||||||
|
margin-left: 160px;
|
||||||
|
margin-top: 10px;
|
||||||
|
input[type=text] {
|
||||||
|
width: 540px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class Admin::UserFieldsController < Admin::AdminController
|
class Admin::UserFieldsController < Admin::AdminController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
field = UserField.create!(params.require(:user_field).permit(:name, :field_type))
|
field = UserField.create!(params.require(:user_field).permit(:name, :field_type, :editable))
|
||||||
render_serialized(field, UserFieldSerializer)
|
render_serialized(field, UserFieldSerializer)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -15,7 +15,8 @@ class Admin::UserFieldsController < Admin::AdminController
|
|||||||
field = UserField.where(id: params.require(:id)).first
|
field = UserField.where(id: params.require(:id)).first
|
||||||
field.name = field_params[:name]
|
field.name = field_params[:name]
|
||||||
field.field_type = field_params[:field_type]
|
field.field_type = field_params[:field_type]
|
||||||
field.save
|
field.editable = field_params[:editable] == "true"
|
||||||
|
field.save!
|
||||||
|
|
||||||
render_serialized(field, UserFieldSerializer)
|
render_serialized(field, UserFieldSerializer)
|
||||||
end
|
end
|
||||||
|
@ -46,6 +46,16 @@ class UsersController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
user = fetch_user_from_params
|
user = fetch_user_from_params
|
||||||
guardian.ensure_can_edit!(user)
|
guardian.ensure_can_edit!(user)
|
||||||
|
|
||||||
|
if params[:user_fields].present?
|
||||||
|
params[:custom_fields] ||= {}
|
||||||
|
UserField.where(editable: true).pluck(:id).each do |fid|
|
||||||
|
val = params[:user_fields][fid.to_s]
|
||||||
|
return render_json_error(I18n.t("login.missing_user_field")) if val.blank?
|
||||||
|
params[:custom_fields]["user_field_#{fid}"] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
json_result(user, serializer: UserSerializer, additional_errors: [:user_profile]) do |u|
|
json_result(user, serializer: UserSerializer, additional_errors: [:user_profile]) do |u|
|
||||||
updater = UserUpdater.new(current_user, user)
|
updater = UserUpdater.new(current_user, user)
|
||||||
updater.update(params)
|
updater.update(params)
|
||||||
@ -162,18 +172,34 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
params.permit(:user_fields)
|
||||||
|
|
||||||
unless SiteSetting.allow_new_registrations
|
unless SiteSetting.allow_new_registrations
|
||||||
render json: { success: false, message: I18n.t("login.new_registrations_disabled") }
|
return fail_with("login.new_registrations_disabled")
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:password] && params[:password].length > User.max_password_length
|
if params[:password] && params[:password].length > User.max_password_length
|
||||||
render json: { success: false, message: I18n.t("login.password_too_long") }
|
return fail_with("login.password_too_long")
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
user = User.new(user_params)
|
user = User.new(user_params)
|
||||||
|
|
||||||
|
# Handle custom fields
|
||||||
|
user_field_ids = UserField.pluck(:id)
|
||||||
|
if user_field_ids.present?
|
||||||
|
if params[:user_fields].blank?
|
||||||
|
return fail_with("login.missing_user_field")
|
||||||
|
else
|
||||||
|
fields = user.custom_fields
|
||||||
|
user_field_ids.each do |fid|
|
||||||
|
field_val = params[:user_fields][fid.to_s]
|
||||||
|
return fail_with("login.missing_user_field") if field_val.blank?
|
||||||
|
fields["user_field_#{fid}"] = field_val
|
||||||
|
end
|
||||||
|
user.custom_fields = fields
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
authentication = UserAuthenticator.new(user, session)
|
authentication = UserAuthenticator.new(user, session)
|
||||||
|
|
||||||
if !authentication.has_authenticator? && !SiteSetting.enable_local_logins
|
if !authentication.has_authenticator? && !SiteSetting.enable_local_logins
|
||||||
@ -194,6 +220,7 @@ class UsersController < ApplicationController
|
|||||||
authentication.finish
|
authentication.finish
|
||||||
activation.finish
|
activation.finish
|
||||||
|
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
success: true,
|
success: true,
|
||||||
active: user.active?,
|
active: user.active?,
|
||||||
@ -550,4 +577,9 @@ class UsersController < ApplicationController
|
|||||||
:active
|
:active
|
||||||
).merge(ip_address: request.ip, registration_ip_address: request.ip)
|
).merge(ip_address: request.ip, registration_ip_address: request.ip)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fail_with(key)
|
||||||
|
render json: { success: false, message: I18n.t(key) }
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -33,6 +33,10 @@ class Site
|
|||||||
@groups ||= Group.order(:name).map { |g| {:id => g.id, :name => g.name}}
|
@groups ||= Group.order(:name).map { |g| {:id => g.id, :name => g.name}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_fields
|
||||||
|
UserField.all
|
||||||
|
end
|
||||||
|
|
||||||
def categories
|
def categories
|
||||||
@categories ||= begin
|
@categories ||= begin
|
||||||
categories = Category
|
categories = Category
|
||||||
|
@ -657,6 +657,18 @@ class User < ActiveRecord::Base
|
|||||||
result.empty? ? I18n.t("user.no_accounts_associated") : result.join(", ")
|
result.empty? ? I18n.t("user.no_accounts_associated") : result.join(", ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_fields
|
||||||
|
return @user_fields if @user_fields
|
||||||
|
user_field_ids = UserField.pluck(:id)
|
||||||
|
if user_field_ids.present?
|
||||||
|
@user_fields = {}
|
||||||
|
user_field_ids.each do |fid|
|
||||||
|
@user_fields[fid.to_s] = custom_fields["user_field_#{fid}"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@user_fields
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def badge_grant
|
def badge_grant
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
class UserFieldSerializer < ApplicationSerializer
|
class UserFieldSerializer < ApplicationSerializer
|
||||||
attributes :id, :name, :field_type
|
attributes :id, :name, :field_type, :editable
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,8 @@ class AdminDetailedUserSerializer < AdminUserSerializer
|
|||||||
:suspend_reason,
|
:suspend_reason,
|
||||||
:primary_group_id,
|
:primary_group_id,
|
||||||
:badge_count,
|
:badge_count,
|
||||||
:warnings_received_count
|
:warnings_received_count,
|
||||||
|
:user_fields
|
||||||
|
|
||||||
has_one :approved_by, serializer: BasicUserSerializer, embed: :objects
|
has_one :approved_by, serializer: BasicUserSerializer, embed: :objects
|
||||||
has_one :api_key, serializer: ApiKeySerializer, embed: :objects
|
has_one :api_key, serializer: ApiKeySerializer, embed: :objects
|
||||||
@ -74,4 +75,12 @@ class AdminDetailedUserSerializer < AdminUserSerializer
|
|||||||
object.has_trust_level?(TrustLevel[2])
|
object.has_trust_level?(TrustLevel[2])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_fields
|
||||||
|
object.user_fields
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_user_fields?
|
||||||
|
object.user_fields.present?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -16,6 +16,7 @@ class SiteSerializer < ApplicationSerializer
|
|||||||
has_many :topic_flag_types, serializer: TopicFlagTypeSerializer, embed: :objects
|
has_many :topic_flag_types, serializer: TopicFlagTypeSerializer, embed: :objects
|
||||||
has_many :trust_levels, embed: :objects
|
has_many :trust_levels, embed: :objects
|
||||||
has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer
|
has_many :archetypes, embed: :objects, serializer: ArchetypeSerializer
|
||||||
|
has_many :user_fields, embed: :objects, serialzer: UserFieldSerializer
|
||||||
|
|
||||||
|
|
||||||
def default_archetype
|
def default_archetype
|
||||||
|
@ -46,7 +46,8 @@ class UserSerializer < BasicUserSerializer
|
|||||||
:notification_count,
|
:notification_count,
|
||||||
:has_title_badges,
|
:has_title_badges,
|
||||||
:edit_history_public,
|
:edit_history_public,
|
||||||
:custom_fields
|
:custom_fields,
|
||||||
|
:user_fields
|
||||||
|
|
||||||
has_one :invited_by, embed: :object, serializer: BasicUserSerializer
|
has_one :invited_by, embed: :object, serializer: BasicUserSerializer
|
||||||
has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer
|
has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer
|
||||||
@ -253,6 +254,14 @@ class UserSerializer < BasicUserSerializer
|
|||||||
can_edit && !SiteSetting.edit_history_visible_to_public
|
can_edit && !SiteSetting.edit_history_visible_to_public
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_fields
|
||||||
|
object.user_fields
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_user_fields?
|
||||||
|
user_fields.present?
|
||||||
|
end
|
||||||
|
|
||||||
def custom_fields
|
def custom_fields
|
||||||
fields = nil
|
fields = nil
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ class UserUpdater
|
|||||||
|
|
||||||
fields = attributes[:custom_fields]
|
fields = attributes[:custom_fields]
|
||||||
if fields.present?
|
if fields.present?
|
||||||
user.custom_fields = fields
|
user.custom_fields = user.custom_fields.merge(fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
User.transaction do
|
User.transaction do
|
||||||
|
@ -579,6 +579,7 @@ en:
|
|||||||
create_account:
|
create_account:
|
||||||
title: "Create New Account"
|
title: "Create New Account"
|
||||||
failed: "Something went wrong, perhaps this email is already registered, try the forgot password link"
|
failed: "Something went wrong, perhaps this email is already registered, try the forgot password link"
|
||||||
|
required_information: "Required Information"
|
||||||
|
|
||||||
forgot_password:
|
forgot_password:
|
||||||
title: "Forgot Password"
|
title: "Forgot Password"
|
||||||
@ -2006,6 +2007,10 @@ en:
|
|||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
cancel: "Cancel"
|
cancel: "Cancel"
|
||||||
delete_confirm: "Are you sure you want to delete that user field?"
|
delete_confirm: "Are you sure you want to delete that user field?"
|
||||||
|
editable:
|
||||||
|
title: "Editable after signup?"
|
||||||
|
enabled: "editable"
|
||||||
|
disabled: "not editable"
|
||||||
|
|
||||||
field_types:
|
field_types:
|
||||||
text: 'Text Field'
|
text: 'Text Field'
|
||||||
|
@ -1103,6 +1103,7 @@ en:
|
|||||||
omniauth_error_unknown: "Something went wrong processing your log in, please try again."
|
omniauth_error_unknown: "Something went wrong processing your log in, please try again."
|
||||||
new_registrations_disabled: "New account registrations are not allowed at this time."
|
new_registrations_disabled: "New account registrations are not allowed at this time."
|
||||||
password_too_long: "Passwords are limited to 200 characters."
|
password_too_long: "Passwords are limited to 200 characters."
|
||||||
|
missing_user_field: "You have not completed all the user fields"
|
||||||
|
|
||||||
user:
|
user:
|
||||||
no_accounts_associated: "No accounts associated"
|
no_accounts_associated: "No accounts associated"
|
||||||
|
5
db/migrate/20140929181930_add_editable_to_user_fields.rb
Normal file
5
db/migrate/20140929181930_add_editable_to_user_fields.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
class AddEditableToUserFields < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :user_fields, :editable, :boolean, default: false, null: false
|
||||||
|
end
|
||||||
|
end
|
@ -531,7 +531,6 @@ describe UsersController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when an Exception is raised' do
|
context 'when an Exception is raised' do
|
||||||
|
|
||||||
[ ActiveRecord::StatementInvalid,
|
[ ActiveRecord::StatementInvalid,
|
||||||
RestClient::Forbidden ].each do |exception|
|
RestClient::Forbidden ].each do |exception|
|
||||||
before { User.any_instance.stubs(:save).raises(exception) }
|
before { User.any_instance.stubs(:save).raises(exception) }
|
||||||
@ -545,6 +544,40 @@ describe UsersController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with custom fields" do
|
||||||
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
|
let!(:another_field) { Fabricate(:user_field) }
|
||||||
|
|
||||||
|
context "without a value for the fields" do
|
||||||
|
let(:create_params) { {name: @user.name, password: 'watwatwat', username: @user.username, email: @user.email} }
|
||||||
|
include_examples 'failed signup'
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with values for the fields" do
|
||||||
|
let(:create_params) { {
|
||||||
|
name: @user.name,
|
||||||
|
password: 'watwatwat',
|
||||||
|
username: @user.username,
|
||||||
|
email: @user.email,
|
||||||
|
user_fields: {
|
||||||
|
user_field.id.to_s => 'value1',
|
||||||
|
another_field.id.to_s => 'value2',
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
|
||||||
|
it "should succeed" do
|
||||||
|
xhr :post, :create, create_params
|
||||||
|
response.should be_success
|
||||||
|
inserted = User.where(email: @user.email).first
|
||||||
|
inserted.should be_present
|
||||||
|
inserted.custom_fields.should be_present
|
||||||
|
inserted.custom_fields["user_field_#{user_field.id}"].should == 'value1'
|
||||||
|
inserted.custom_fields["user_field_#{another_field.id}"].should == 'value2'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context '.username' do
|
context '.username' do
|
||||||
@ -844,12 +877,10 @@ describe UsersController do
|
|||||||
|
|
||||||
context 'with authenticated user' do
|
context 'with authenticated user' do
|
||||||
context 'with permission to update' do
|
context 'with permission to update' do
|
||||||
|
let!(:user) { log_in(:user) }
|
||||||
|
|
||||||
it 'allows the update' do
|
it 'allows the update' do
|
||||||
user = Fabricate(:user, name: 'Billy Bob')
|
|
||||||
log_in_user(user)
|
|
||||||
|
|
||||||
put :update, username: user.username, name: 'Jim Tom', custom_fields: {test: :it}
|
put :update, username: user.username, name: 'Jim Tom', custom_fields: {test: :it}
|
||||||
|
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
|
|
||||||
user.reload
|
user.reload
|
||||||
@ -858,14 +889,42 @@ describe UsersController do
|
|||||||
expect(user.custom_fields['test']).to eq 'it'
|
expect(user.custom_fields['test']).to eq 'it'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns user JSON' do
|
context "with user fields" do
|
||||||
user = log_in
|
context "an editable field" do
|
||||||
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
|
|
||||||
|
it "should update the user field" do
|
||||||
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
||||||
|
expect(response).to be_success
|
||||||
|
expect(user.user_fields[user_field.id.to_s]).to eq 'happy'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "cannot be updated to blank" do
|
||||||
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => '' }
|
||||||
|
response.should_not be_success
|
||||||
|
user.user_fields[user_field.id.to_s].should_not == 'happy'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "uneditable field" do
|
||||||
|
let!(:user_field) { Fabricate(:user_field, editable: false) }
|
||||||
|
|
||||||
|
it "does not update the user field" do
|
||||||
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
||||||
|
expect(response).to be_success
|
||||||
|
expect(user.user_fields[user_field.id.to_s]).to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns user JSON' do
|
||||||
put :update, username: user.username
|
put :update, username: user.username
|
||||||
|
|
||||||
json = JSON.parse(response.body)
|
json = JSON.parse(response.body)
|
||||||
expect(json['user']['id']).to eq user.id
|
expect(json['user']['id']).to eq user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without permission to update' do
|
context 'without permission to update' do
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
Fabricator(:user_field) do
|
Fabricator(:user_field) do
|
||||||
name { sequence(:name) {|i| "field_#{i}" } }
|
name { sequence(:name) {|i| "field_#{i}" } }
|
||||||
field_type 'text'
|
field_type 'text'
|
||||||
|
editable true
|
||||||
end
|
end
|
||||||
|
3
test/javascripts/fixtures/site_fixtures.js.es6
Normal file
3
test/javascripts/fixtures/site_fixtures.js.es6
Normal file
File diff suppressed because one or more lines are too long
@ -1,9 +1,13 @@
|
|||||||
/* global asyncTest */
|
/* global asyncTest */
|
||||||
/* exported integration, testController, controllerFor, asyncTestDiscourse, fixture */
|
|
||||||
function integration(name, options) {
|
import siteFixtures from 'fixtures/site_fixtures';
|
||||||
|
|
||||||
|
export function integration(name, options) {
|
||||||
module("Integration: " + name, {
|
module("Integration: " + name, {
|
||||||
setup: function() {
|
setup: function() {
|
||||||
Ember.run(Discourse, Discourse.advanceReadiness);
|
Ember.run(Discourse, Discourse.advanceReadiness);
|
||||||
|
|
||||||
|
var siteJson = siteFixtures['site.json'].site;
|
||||||
if (options) {
|
if (options) {
|
||||||
if (options.setup) {
|
if (options.setup) {
|
||||||
options.setup.call(this);
|
options.setup.call(this);
|
||||||
@ -16,7 +20,12 @@ function integration(name, options) {
|
|||||||
if (options.settings) {
|
if (options.settings) {
|
||||||
Discourse.SiteSettings = jQuery.extend(true, Discourse.SiteSettings, options.settings);
|
Discourse.SiteSettings = jQuery.extend(true, Discourse.SiteSettings, options.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.site) {
|
||||||
|
Discourse.Site.resetCurrent(Discourse.Site.create(jQuery.extend(true, {}, siteJson, options.site)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Discourse.reset();
|
Discourse.reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -30,13 +39,13 @@ function integration(name, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function controllerFor(controller, model) {
|
export function controllerFor(controller, model) {
|
||||||
controller = Discourse.__container__.lookup('controller:' + controller);
|
controller = Discourse.__container__.lookup('controller:' + controller);
|
||||||
if (model) { controller.set('model', model ); }
|
if (model) { controller.set('model', model ); }
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
function asyncTestDiscourse(text, func) {
|
export function asyncTestDiscourse(text, func) {
|
||||||
asyncTest(text, function () {
|
asyncTest(text, function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
Ember.run(function () {
|
Ember.run(function () {
|
||||||
@ -45,7 +54,7 @@ function asyncTestDiscourse(text, func) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixture(selector) {
|
export function fixture(selector) {
|
||||||
if (selector) {
|
if (selector) {
|
||||||
return $("#qunit-fixture").find(selector);
|
return $("#qunit-fixture").find(selector);
|
||||||
}
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import { integration } from "helpers/qunit-helpers";
|
||||||
|
|
||||||
|
integration("Create Account - User Fields", {
|
||||||
|
site: {
|
||||||
|
user_fields: [{"id":34,"name":"I've read the terms of service","field_type":"confirm"},
|
||||||
|
{"id":35,"name":"What is your pet's name?","field_type":"text"}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("create account with user fields", function() {
|
||||||
|
visit("/");
|
||||||
|
click("header .sign-up-button");
|
||||||
|
|
||||||
|
andThen(function() {
|
||||||
|
ok(exists('.create-account'), "it shows the create account modal");
|
||||||
|
ok(exists('.user-field'), "it has at least one user field");
|
||||||
|
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled at first');
|
||||||
|
});
|
||||||
|
|
||||||
|
fillIn('#new-account-name', 'Dr. Good Tuna');
|
||||||
|
fillIn('#new-account-password', 'cool password bro');
|
||||||
|
fillIn('#new-account-email', 'good.tuna@test.com');
|
||||||
|
fillIn('#new-account-username', 'goodtuna');
|
||||||
|
|
||||||
|
andThen(function() {
|
||||||
|
ok(exists('#username-validation.good'), 'the username validation is good');
|
||||||
|
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is still disabled due to lack of user fields');
|
||||||
|
});
|
||||||
|
|
||||||
|
fillIn(".user-field input[type=text]", "Barky");
|
||||||
|
|
||||||
|
andThen(function() {
|
||||||
|
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
click(".user-field input[type=checkbox]");
|
||||||
|
andThen(function() {
|
||||||
|
not(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked');
|
||||||
|
});
|
||||||
|
|
||||||
|
click(".user-field input[type=checkbox]");
|
||||||
|
andThen(function() {
|
||||||
|
ok(exists('.modal-footer .btn-primary:disabled'), 'unclicking the checkbox disables the submit');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -20,16 +20,18 @@ test('has a postStream', function() {
|
|||||||
equal(postStream.get('topic'), topic, "the postStream has a reference back to the topic");
|
equal(postStream.get('topic'), topic, "the postStream has a reference back to the topic");
|
||||||
});
|
});
|
||||||
|
|
||||||
var category = _.first(Discourse.Category.list());
|
|
||||||
|
|
||||||
test('category relationship', function() {
|
test('category relationship', function() {
|
||||||
// It finds the category by id
|
// It finds the category by id
|
||||||
var topic = Discourse.Topic.create({id: 1111, category_id: category.get('id') });
|
var category = Discourse.Category.list()[0],
|
||||||
|
topic = Discourse.Topic.create({id: 1111, category_id: category.get('id') });
|
||||||
|
|
||||||
equal(topic.get('category'), category);
|
equal(topic.get('category'), category);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("updateFromJson", function() {
|
test("updateFromJson", function() {
|
||||||
var topic = Discourse.Topic.create({id: 1234});
|
var topic = Discourse.Topic.create({id: 1234}),
|
||||||
|
category = Discourse.Category.list()[0];
|
||||||
|
|
||||||
topic.updateFromJson({
|
topic.updateFromJson({
|
||||||
post_stream: [1,2,3],
|
post_stream: [1,2,3],
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
//= require sinon-qunit-1.0.0
|
//= require sinon-qunit-1.0.0
|
||||||
//= require jshint
|
//= require jshint
|
||||||
|
|
||||||
//= require helpers/qunit_helpers
|
//= require helpers/qunit-helpers
|
||||||
//= require helpers/assertions
|
//= require helpers/assertions
|
||||||
|
|
||||||
//= require helpers/init-ember-qunit
|
//= require helpers/init-ember-qunit
|
||||||
@ -50,7 +50,6 @@
|
|||||||
//= require_tree ./lib
|
//= require_tree ./lib
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
//= require_self
|
//= require_self
|
||||||
//= require jshint_all
|
|
||||||
|
|
||||||
// sinon settings
|
// sinon settings
|
||||||
sinon.config = {
|
sinon.config = {
|
||||||
@ -87,6 +86,7 @@ if (window.Logster) {
|
|||||||
|
|
||||||
var origDebounce = Ember.run.debounce,
|
var origDebounce = Ember.run.debounce,
|
||||||
createPretendServer = require('helpers/create-pretender', null, null, false).default,
|
createPretendServer = require('helpers/create-pretender', null, null, false).default,
|
||||||
|
fixtures = require('fixtures/site_fixtures', null, null, false).default,
|
||||||
server;
|
server;
|
||||||
|
|
||||||
QUnit.testStart(function(ctx) {
|
QUnit.testStart(function(ctx) {
|
||||||
@ -97,6 +97,7 @@ QUnit.testStart(function(ctx) {
|
|||||||
Discourse.BaseUri = "/";
|
Discourse.BaseUri = "/";
|
||||||
Discourse.BaseUrl = "";
|
Discourse.BaseUrl = "";
|
||||||
Discourse.User.resetCurrent();
|
Discourse.User.resetCurrent();
|
||||||
|
Discourse.Site.resetCurrent(Discourse.Site.create(fixtures['site.json'].site));
|
||||||
PreloadStore.reset();
|
PreloadStore.reset();
|
||||||
|
|
||||||
window.sandbox = sinon.sandbox.create();
|
window.sandbox = sinon.sandbox.create();
|
||||||
@ -121,6 +122,15 @@ QUnit.testDone(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Load ES6 tests
|
// Load ES6 tests
|
||||||
|
var helpers = require("helpers/qunit-helpers");
|
||||||
|
|
||||||
|
// TODO: Replace with proper imports rather than globals
|
||||||
|
window.asyncTestDiscourse = helpers.asyncTestDiscourse;
|
||||||
|
window.controllerFor = helpers.controllerFor;
|
||||||
|
window.fixture = helpers.fixture;
|
||||||
|
window.integration = helpers.integration;
|
||||||
|
|
||||||
|
|
||||||
Ember.keys(requirejs.entries).forEach(function(entry) {
|
Ember.keys(requirejs.entries).forEach(function(entry) {
|
||||||
if ((/\-test/).test(entry)) {
|
if ((/\-test/).test(entry)) {
|
||||||
require(entry, null, null, true);
|
require(entry, null, null, true);
|
||||||
|
Reference in New Issue
Block a user