Adds support for a description to user fields.

This commit is contained in:
Robin Ward 2014-10-02 15:56:28 -04:00
parent 295a3c108e
commit 381814fd5d
22 changed files with 157 additions and 60 deletions

View File

@ -13,14 +13,18 @@ export default Ember.ObjectController.extend(BufferedContent, {
save: function() { save: function() {
var self = this; var self = this;
var attrs = this.get('buffered').getProperties('name', 'field_type', 'editable'); var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable');
this.get('model').save(attrs).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(); self.commitBuffer();
}).catch(function() { }).catch(function(e) {
bootbox.alert(I18n.t('generic_error')); var msg = I18n.t("generic_error");
if (e.responseJSON && e.responseJSON.errors) {
msg = I18n.t("generic_error_with_reason", {error: e.responseJSON.errors.join('. ')});
}
bootbox.alert(msg);
}); });
}, },

View File

@ -3,6 +3,11 @@ 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),
userFieldsDescription: function() {
return I18n.t('admin.user_fields.description');
}.property(),
userFieldsName: function() { userFieldsName: function() {
return I18n.t('admin.user_fields.name'); return I18n.t('admin.user_fields.name');
}.property(), }.property(),

View File

@ -1,28 +1,36 @@
<div class='user-fields'> <div class='user-fields'>
<h2>{{i18n admin.user_fields.title}}</h2> <h2>{{i18n admin.user_fields.title}}</h2>
<p class="desc">{{i18n admin.user_fields.description}}</p> <p class="desc">{{i18n admin.user_fields.help}}</p>
{{#if model}} {{#if model}}
{{#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='row'>
{{input value=f.buffered.name class="user-field-name" placeholder=userFieldsName}} <div class='form-element'>
{{input value=f.buffered.name class="user-field-name" placeholder=userFieldsName}}
</div>
<div class='form-element'>
{{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>
</div>
<div class='form-element controls'>
<button {{action "save"}}class='btn btn-primary'>{{fa-icon 'check'}} {{i18n admin.user_fields.save}}</button>
<button {{action "cancel"}} class='btn btn-danger'>{{fa-icon 'times'}} {{i18n admin.user_fields.cancel}}</button>
</div>
</div> </div>
<div class='form-element'> <div class="row">
{{combo-box content=fieldTypes valueAttribute="id" value=f.buffered.field_type}} <div class='form-element'>
</div> {{input value=f.buffered.description class="user-field-desc" placeholder=userFieldsDescription}}
<div class='form-element'> </div>
<label>
{{input type="checkbox" checked=f.buffered.editable}} {{i18n admin.user_fields.editable.title}}
</label>
</div>
<div class='form-element controls'>
<button {{action "save"}}class='btn btn-primary'>{{fa-icon 'check'}} {{i18n admin.user_fields.save}}</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="row">
<div class='form-display'><strong>{{f.name}}</strong></div>
<div class='form-display'>{{f.fieldName}}</div> <div class='form-display'>{{f.fieldName}}</div>
<div class='form-display'> <div class='form-display'>
{{#if f.editable}} {{#if f.editable}}
@ -35,6 +43,11 @@
<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>
<button {{action "destroy"}}class='btn btn-danger'>{{fa-icon 'trash-o'}} {{i18n admin.user_fields.delete}}</button> <button {{action "destroy"}}class='btn btn-danger'>{{fa-icon 'trash-o'}} {{i18n admin.user_fields.delete}}</button>
</div> </div>
</div>
<div class="row">
{{f.description}}
</div>
{{/if}} {{/if}}
<div class='clearfix'></div> <div class='clearfix'></div>
{{/each}} {{/each}}

View File

@ -1,5 +1,5 @@
export default Ember.Component.extend({ export default Ember.Component.extend({
classNameBindings: [':user-field'], classNameBindings: [':user-field', 'field.field_type'],
layoutName: function() { layoutName: function() {
return "components/user-fields/" + this.get('field.field_type'); return "components/user-fields/" + this.get('field.field_type');
}.property('field.field_type') }.property('field.field_type')

View File

@ -22,7 +22,7 @@ export default ObjectController.extend(CanCheckEmails, {
var siteUserFields = this.site.get('user_fields'); var siteUserFields = this.site.get('user_fields');
if (!Ember.empty(siteUserFields)) { if (!Ember.empty(siteUserFields)) {
var userFields = this.get('user_fields'); var userFields = this.get('user_fields');
return siteUserFields.filterProperty('editable', true).map(function(uf) { return siteUserFields.filterProperty('editable', true).sortBy('field_type').map(function(uf) {
var val = userFields ? userFields[uf.get('id').toString()] : null; var val = userFields ? userFields[uf.get('id').toString()] : null;
return Ember.Object.create({value: val, field: uf}); return Ember.Object.create({value: val, field: uf});
}); });

View File

@ -1,3 +1,3 @@
<label> <div class='controls'>
{{input checked=value type="checkbox"}} {{{field.name}}} <label>{{input checked=value type="checkbox"}} {{field.description}}</label>
</label> </div>

View File

@ -1,4 +1,5 @@
<label> <label>{{{field.name}}}</label>
{{{field.name}}} <div class='controls'>
{{input value=value}} {{input value=value}}
</label> <p>{{field.description}}</p>
</div>

View File

@ -71,6 +71,7 @@
</table> </table>
{{log userFields}}
{{#if userFields}} {{#if userFields}}
<div class='user-fields'> <div class='user-fields'>
{{#each userFields}} {{#each userFields}}

View File

@ -179,13 +179,13 @@
{{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>
{{#each userFields}}
{{user-field field=field value=value}}
{{/each}}
<div class="control-group category"> <div class="control-group category">
<label class="control-label">{{i18n user.categories_settings}}</label> <label class="control-label">{{i18n user.categories_settings}}</label>
<div class="controls category-controls"> <div class="controls category-controls">

View File

@ -12,27 +12,33 @@
display: none; display: none;
} }
.create-account {
.user-fields { .user-field.confirm {
margin-top: 20px;
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 { .user-field {
label: { label {
display: block; width: 92px;
float: left;
} }
input[type=text] { input[type=text] {
width: 80%; width: 220px;
display: block; margin-bottom: 0;
} }
input[type=checkbox] { .controls {
margin-right: 5px; margin-left: 92px;
label {
width: auto;
text-align: left;
font-weight: normal;
float: auto;
}
p {
color: scale-color($primary, $lightness: 50%);
margin: 0;
}
} }
margin-bottom: 20px; clear: both;
} }
} }

View File

@ -59,4 +59,5 @@
.tos-agree { .tos-agree {
margin-bottom: 12px; margin-bottom: 12px;
} }
} }

View File

@ -75,6 +75,14 @@
} }
} }
.form-horizontal .control-group.other {
margin-bottom: 0;
}
.form-horizontal .control-group.category {
margin-top: 18px;
}
.user-navigation { .user-navigation {
width: 21.62%; width: 21.62%;
margin-right: 1.8018%; margin-right: 1.8018%;
@ -427,12 +435,36 @@
background-color: #c22020; background-color: #c22020;
} }
.user-field.text {
padding-top: 18px;
}
.user-field { .user-field {
margin-left: 160px; label {
margin-top: 10px; width: 140px;
input[type=text] { float: left;
width: 540px; text-align: right;
display: block; font-weight: bold;
} }
input[type=text] {
width: 530px;
}
.controls {
label {
width: auto;
text-align: left;
font-weight: normal;
float: auto;
}
p {
color: scale-color($primary, $lightness: 50%);
margin-top: 5px;
margin-bottom: 10px;
font-size: 80%;
line-height: 1.4em;
}
}
clear: both;
margin-bottom: 10px;
} }
} }

View File

@ -52,3 +52,23 @@ a#forgot-password-link {clear: left; float: left; }
} }
} }
} }
.create-account {
.user-field.confirm {
margin-top: 10px;
margin-bottom: 10px;
}
.user-field {
margin-top: 10px;
label {
width: 85px;
}
input[type=text] {
margin-top: 0;
width: 184px;
}
.controls {
margin-left: 85px;
}
}
}

View File

@ -1,8 +1,10 @@
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, :editable)) field = UserField.new(params.require(:user_field).permit(:name, :field_type, :editable, :description))
render_serialized(field, UserFieldSerializer) json_result(field, serializer: UserFieldSerializer) do
field.save
end
end end
def index def index
@ -15,10 +17,12 @@ 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.description = field_params[:description]
field.editable = field_params[:editable] == "true" field.editable = field_params[:editable] == "true"
field.save!
render_serialized(field, UserFieldSerializer) json_result(field, serializer: UserFieldSerializer) do
field.save
end
end end
def destroy def destroy

View File

@ -51,6 +51,7 @@ class UsersController < ApplicationController
params[:custom_fields] ||= {} params[:custom_fields] ||= {}
UserField.where(editable: true).pluck(:id).each do |fid| UserField.where(editable: true).pluck(:id).each do |fid|
val = params[:user_fields][fid.to_s] val = params[:user_fields][fid.to_s]
val = nil if val === "false"
return render_json_error(I18n.t("login.missing_user_field")) if val.blank? return render_json_error(I18n.t("login.missing_user_field")) if val.blank?
params[:custom_fields]["user_field_#{fid}"] = val params[:custom_fields]["user_field_#{fid}"] = val
end end

View File

@ -75,6 +75,7 @@ class Site
return { return {
periods: TopTopic.periods.map(&:to_s), periods: TopTopic.periods.map(&:to_s),
filters: Discourse.filters.map(&:to_s), filters: Discourse.filters.map(&:to_s),
user_fields: UserField.all
}.to_json }.to_json
end end

View File

@ -1,4 +1,3 @@
class UserField < ActiveRecord::Base class UserField < ActiveRecord::Base
validates_presence_of :name, :field_type validates_presence_of :name, :description, :field_type
end end

View File

@ -1,3 +1,3 @@
class UserFieldSerializer < ApplicationSerializer class UserFieldSerializer < ApplicationSerializer
attributes :id, :name, :field_type, :editable attributes :id, :name, :description, :field_type, :editable
end end

View File

@ -1999,11 +1999,12 @@ en:
user_fields: user_fields:
title: "User Fields" title: "User Fields"
description: "Any fields added here will be required from users when they sign up." help: "Any fields added here will be required from users when they sign up."
create: "Create User Field" create: "Create User Field"
untitled: "Untitled" untitled: "Untitled"
name: "Field Name" name: "Field Name"
type: "Field Type" type: "Field Type"
description: "Field Description"
save: "Save" save: "Save"
edit: "Edit" edit: "Edit"
delete: "Delete" delete: "Delete"

View File

@ -0,0 +1,7 @@
class AddDescriptionToUserFields < ActiveRecord::Migration
def change
add_column :user_fields, :description, :string, null: true
execute "UPDATE user_fields SET description=name"
change_column :user_fields, :description, :string, null: false
end
end

View File

@ -12,7 +12,7 @@ describe Admin::UserFieldsController do
context '.create' do context '.create' do
it "creates a user field" do it "creates a user field" do
-> { -> {
xhr :post, :create, {user_field: {name: 'hello', field_type: 'text'} } xhr :post, :create, {user_field: {name: 'hello', description: 'hello desc', field_type: 'text'} }
response.should be_success response.should be_success
}.should change(UserField, :count).by(1) }.should change(UserField, :count).by(1)
end end
@ -44,7 +44,7 @@ describe Admin::UserFieldsController do
let!(:user_field) { Fabricate(:user_field) } let!(:user_field) { Fabricate(:user_field) }
it "returns a list of user fields" do it "returns a list of user fields" do
xhr :put, :update, id: user_field.id, user_field: {name: 'fraggle', field_type: 'confirm'} xhr :put, :update, id: user_field.id, user_field: {name: 'fraggle', field_type: 'confirm', description: 'muppet'}
response.should be_success response.should be_success
user_field.reload user_field.reload
user_field.name.should == 'fraggle' user_field.name.should == 'fraggle'

View File

@ -1,5 +1,6 @@
Fabricator(:user_field) do Fabricator(:user_field) do
name { sequence(:name) {|i| "field_#{i}" } } name { sequence(:name) {|i| "field_#{i}" } }
description "user field description"
field_type 'text' field_type 'text'
editable true editable true
end end