mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-02-25 07:54:11 -05:00
FEATURE: Support for a required
setting on user fields.
This commit is contained in:
parent
9f2be41710
commit
f9a8f6d6ce
16 changed files with 110 additions and 48 deletions
|
@ -9,11 +9,23 @@ export default Ember.ObjectController.extend(BufferedContent, {
|
||||||
return UserField.fieldTypeById(this.get('field_type')).get('name');
|
return UserField.fieldTypeById(this.get('field_type')).get('name');
|
||||||
}.property('field_type'),
|
}.property('field_type'),
|
||||||
|
|
||||||
|
flags: function() {
|
||||||
|
var ret = [];
|
||||||
|
if (this.get('editable')) {
|
||||||
|
ret.push(I18n.t('admin.user_fields.editable.enabled'));
|
||||||
|
}
|
||||||
|
if (this.get('required')) {
|
||||||
|
ret.push(I18n.t('admin.user_fields.required.enabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.join(', ');
|
||||||
|
}.property('editable', 'required'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
save: function() {
|
save: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable');
|
var attrs = this.get('buffered').getProperties('name', 'description', 'field_type', 'editable', 'required');
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -11,12 +11,10 @@
|
||||||
{{input value=f.buffered.name class="user-field-name" placeholder=userFieldsName}}
|
{{input value=f.buffered.name class="user-field-name" placeholder=userFieldsName}}
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element'>
|
<div class='form-element'>
|
||||||
{{combo-box content=fieldTypes valueAttribute="id" value=f.buffered.field_type}}
|
{{input value=f.buffered.description class="user-field-desc" placeholder=userFieldsDescription}}
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element'>
|
<div class='form-element'>
|
||||||
<label>
|
{{combo-box content=fieldTypes valueAttribute="id" value=f.buffered.field_type}}
|
||||||
{{input type="checkbox" checked=f.buffered.editable}} {{i18n admin.user_fields.editable.title}}
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class='form-element controls'>
|
<div class='form-element controls'>
|
||||||
<button {{action "save"}}class='btn btn-primary'>{{fa-icon 'check'}} {{i18n admin.user_fields.save}}</button>
|
<button {{action "save"}}class='btn btn-primary'>{{fa-icon 'check'}} {{i18n admin.user_fields.save}}</button>
|
||||||
|
@ -25,29 +23,29 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class='form-element'>
|
<div class='form-element'>
|
||||||
{{input value=f.buffered.description class="user-field-desc" placeholder=userFieldsDescription}}
|
<label>
|
||||||
|
{{input type="checkbox" checked=f.buffered.editable}} {{i18n admin.user_fields.editable.title}}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class='form-element'>
|
||||||
|
<label>
|
||||||
|
{{input type="checkbox" checked=f.buffered.required}} {{i18n admin.user_fields.required.title}}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class='form-display'><strong>{{f.name}}</strong></div>
|
<div class='form-display'><strong>{{f.name}}</strong></div>
|
||||||
|
<div class='form-display'>{{{f.description}}}</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}}
|
|
||||||
{{i18n admin.user_fields.editable.enabled}}
|
|
||||||
{{else}}
|
|
||||||
{{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>
|
||||||
<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>
|
||||||
<div class="row">
|
<div class="row">{{f.flags}}</div>
|
||||||
{{f.description}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class='clearfix'></div>
|
<div class='clearfix'></div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -51,6 +51,7 @@ export default DiscourseController.extend(ModalFunctionality, {
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
var userFields = this.get('userFields');
|
var userFields = this.get('userFields');
|
||||||
|
if (userFields) { userFields = userFields.filterProperty('field.required'); }
|
||||||
if (!Ember.empty(userFields)) {
|
if (!Ember.empty(userFields)) {
|
||||||
var anyEmpty = userFields.any(function(uf) {
|
var anyEmpty = userFields.any(function(uf) {
|
||||||
var val = uf.get('value');
|
var val = uf.get('value');
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<label>{{{field.name}}}</label>
|
<label>{{{field.name}}}</label>
|
||||||
<div class='controls'>
|
<div class='controls'>
|
||||||
{{input value=value}}
|
{{input value=value}}
|
||||||
|
{{#if field.required}}<span class='required'>*</span>{{/if}}
|
||||||
<p>{{{field.description}}}</p>
|
<p>{{{field.description}}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
}
|
}
|
||||||
.controls {
|
.controls {
|
||||||
margin-left: 92px;
|
margin-left: 92px;
|
||||||
|
margin-bottom: 15px;
|
||||||
label {
|
label {
|
||||||
width: auto;
|
width: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
|
@ -15,6 +15,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-field {
|
||||||
|
.required {
|
||||||
|
text-align: top;
|
||||||
|
color: $danger;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.end-of-stream {
|
.end-of-stream {
|
||||||
border: 3px solid $primary;
|
border: 3px solid $primary;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -63,6 +63,7 @@ a#forgot-password-link {clear: left; float: left; }
|
||||||
label {
|
label {
|
||||||
width: 85px;
|
width: 85px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text] {
|
input[type=text] {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
width: 184px;
|
width: 184px;
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
class Admin::UserFieldsController < Admin::AdminController
|
class Admin::UserFieldsController < Admin::AdminController
|
||||||
|
|
||||||
|
def self.columns
|
||||||
|
[:name, :field_type, :editable, :description, :required]
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
field = UserField.new(params.require(:user_field).permit(:name, :field_type, :editable, :description))
|
field = UserField.new(params.require(:user_field).permit(*Admin::UserFieldsController.columns))
|
||||||
json_result(field, serializer: UserFieldSerializer) do
|
json_result(field, serializer: UserFieldSerializer) do
|
||||||
field.save
|
field.save
|
||||||
end
|
end
|
||||||
|
@ -15,10 +19,10 @@ class Admin::UserFieldsController < Admin::AdminController
|
||||||
field_params = params.require(:user_field)
|
field_params = params.require(:user_field)
|
||||||
|
|
||||||
field = UserField.where(id: params.require(:id)).first
|
field = UserField.where(id: params.require(:id)).first
|
||||||
field.name = field_params[:name]
|
|
||||||
field.field_type = field_params[:field_type]
|
Admin::UserFieldsController.columns.each do |col|
|
||||||
field.description = field_params[:description]
|
field.send("#{col}=", field_params[col] || false)
|
||||||
field.editable = field_params[:editable] == "true"
|
end
|
||||||
|
|
||||||
json_result(field, serializer: UserFieldSerializer) do
|
json_result(field, serializer: UserFieldSerializer) do
|
||||||
field.save
|
field.save
|
||||||
|
|
|
@ -49,11 +49,12 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
if params[:user_fields].present?
|
if params[:user_fields].present?
|
||||||
params[:custom_fields] ||= {}
|
params[:custom_fields] ||= {}
|
||||||
UserField.where(editable: true).pluck(:id).each do |fid|
|
UserField.where(editable: true).each do |f|
|
||||||
val = params[:user_fields][fid.to_s]
|
val = params[:user_fields][f.id.to_s]
|
||||||
val = nil if val === "false"
|
val = nil if val === "false"
|
||||||
return render_json_error(I18n.t("login.missing_user_field")) if val.blank?
|
|
||||||
params[:custom_fields]["user_field_#{fid}"] = val
|
return render_json_error(I18n.t("login.missing_user_field")) if val.blank? && f.required?
|
||||||
|
params[:custom_fields]["user_field_#{f.id}"] = val
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -188,16 +189,19 @@ class UsersController < ApplicationController
|
||||||
user = User.new(user_params)
|
user = User.new(user_params)
|
||||||
|
|
||||||
# Handle custom fields
|
# Handle custom fields
|
||||||
user_field_ids = UserField.pluck(:id)
|
user_fields = UserField.all
|
||||||
if user_field_ids.present?
|
if user_fields.present?
|
||||||
if params[:user_fields].blank?
|
if params[:user_fields].blank? && UserField.where(required: true).exists?
|
||||||
return fail_with("login.missing_user_field")
|
return fail_with("login.missing_user_field")
|
||||||
else
|
else
|
||||||
fields = user.custom_fields
|
fields = user.custom_fields
|
||||||
user_field_ids.each do |fid|
|
user_fields.each do |f|
|
||||||
field_val = params[:user_fields][fid.to_s]
|
field_val = params[:user_fields][f.id.to_s]
|
||||||
return fail_with("login.missing_user_field") if field_val.blank?
|
if field_val.blank?
|
||||||
fields["user_field_#{fid}"] = field_val
|
return fail_with("login.missing_user_field") if f.required?
|
||||||
|
else
|
||||||
|
fields["user_field_#{f.id}"] = field_val
|
||||||
|
end
|
||||||
end
|
end
|
||||||
user.custom_fields = fields
|
user.custom_fields = fields
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
class UserFieldSerializer < ApplicationSerializer
|
class UserFieldSerializer < ApplicationSerializer
|
||||||
attributes :id, :name, :description, :field_type, :editable
|
attributes :id,
|
||||||
|
:name,
|
||||||
|
:description,
|
||||||
|
:field_type,
|
||||||
|
:editable,
|
||||||
|
:required
|
||||||
end
|
end
|
||||||
|
|
|
@ -2019,6 +2019,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?"
|
||||||
|
required:
|
||||||
|
title: "Required at signup?"
|
||||||
|
enabled: "required"
|
||||||
|
disabled: "not required"
|
||||||
editable:
|
editable:
|
||||||
title: "Editable after signup?"
|
title: "Editable after signup?"
|
||||||
enabled: "editable"
|
enabled: "editable"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddRequiredSignupToUserFields < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :user_fields, :required, :boolean, default: true, null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -32,7 +32,7 @@ describe Admin::UserFieldsController do
|
||||||
context '.destroy' do
|
context '.destroy' do
|
||||||
let!(:user_field) { Fabricate(:user_field) }
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
|
|
||||||
it "returns a list of user fields" do
|
it "deletes the user field" do
|
||||||
-> {
|
-> {
|
||||||
xhr :delete, :destroy, id: user_field.id
|
xhr :delete, :destroy, id: user_field.id
|
||||||
response.should be_success
|
response.should be_success
|
||||||
|
@ -43,7 +43,7 @@ describe Admin::UserFieldsController do
|
||||||
context '.update' do
|
context '.update' do
|
||||||
let!(:user_field) { Fabricate(:user_field) }
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
|
|
||||||
it "returns a list of user fields" do
|
it "updates the user field" do
|
||||||
xhr :put, :update, id: user_field.id, user_field: {name: 'fraggle', field_type: 'confirm', description: 'muppet'}
|
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
|
||||||
|
|
|
@ -559,6 +559,7 @@ describe UsersController do
|
||||||
context "with custom fields" do
|
context "with custom fields" do
|
||||||
let!(:user_field) { Fabricate(:user_field) }
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
let!(:another_field) { Fabricate(:user_field) }
|
let!(:another_field) { Fabricate(:user_field) }
|
||||||
|
let!(:optional_field) { Fabricate(:user_field, required: false) }
|
||||||
|
|
||||||
context "without a value for the fields" do
|
context "without a value for the fields" do
|
||||||
let(:create_params) { {name: @user.name, password: 'watwatwat', username: @user.username, email: @user.email} }
|
let(:create_params) { {name: @user.name, password: 'watwatwat', username: @user.username, email: @user.email} }
|
||||||
|
@ -577,7 +578,7 @@ describe UsersController do
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
|
|
||||||
it "should succeed" do
|
it "should succeed without the optional field" do
|
||||||
xhr :post, :create, create_params
|
xhr :post, :create, create_params
|
||||||
response.should be_success
|
response.should be_success
|
||||||
inserted = User.where(email: @user.email).first
|
inserted = User.where(email: @user.email).first
|
||||||
|
@ -585,6 +586,19 @@ describe UsersController do
|
||||||
inserted.custom_fields.should be_present
|
inserted.custom_fields.should be_present
|
||||||
inserted.custom_fields["user_field_#{user_field.id}"].should == 'value1'
|
inserted.custom_fields["user_field_#{user_field.id}"].should == 'value1'
|
||||||
inserted.custom_fields["user_field_#{another_field.id}"].should == 'value2'
|
inserted.custom_fields["user_field_#{another_field.id}"].should == 'value2'
|
||||||
|
inserted.custom_fields["user_field_#{optional_field.id}"].should be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should succeed with the optional field" do
|
||||||
|
create_params[:user_fields][optional_field.id.to_s] = 'value3'
|
||||||
|
xhr :post, :create, create_params.merge(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'
|
||||||
|
inserted.custom_fields["user_field_#{optional_field.id}"].should == 'value3'
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -904,6 +918,7 @@ describe UsersController do
|
||||||
context "with user fields" do
|
context "with user fields" do
|
||||||
context "an editable field" do
|
context "an editable field" do
|
||||||
let!(:user_field) { Fabricate(:user_field) }
|
let!(:user_field) { Fabricate(:user_field) }
|
||||||
|
let!(:optional_field) { Fabricate(:user_field, required: false ) }
|
||||||
|
|
||||||
it "should update the user field" do
|
it "should update the user field" do
|
||||||
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' }
|
||||||
|
|
|
@ -3,4 +3,5 @@ Fabricator(:user_field) do
|
||||||
description "user field description"
|
description "user field description"
|
||||||
field_type 'text'
|
field_type 'text'
|
||||||
editable true
|
editable true
|
||||||
|
required true
|
||||||
end
|
end
|
|
@ -2,8 +2,9 @@ import { integration } from "helpers/qunit-helpers";
|
||||||
|
|
||||||
integration("Create Account - User Fields", {
|
integration("Create Account - User Fields", {
|
||||||
site: {
|
site: {
|
||||||
user_fields: [{"id":34,"name":"I've read the terms of service","field_type":"confirm"},
|
user_fields: [{"id":34,"name":"I've read the terms of service","field_type":"confirm","required":true},
|
||||||
{"id":35,"name":"What is your pet's name?","field_type":"text"}]
|
{"id":35,"name":"What is your pet's name?","field_type":"text","required":true},
|
||||||
|
{"id":36,"name":"What's your dad like?","field_type":"text","required":false}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ test("create account with user fields", function() {
|
||||||
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is still disabled due to lack of user fields');
|
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");
|
fillIn(".user-field input[type=text]:first", "Barky");
|
||||||
|
|
||||||
andThen(function() {
|
andThen(function() {
|
||||||
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked');
|
ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked');
|
||||||
|
@ -35,7 +36,7 @@ test("create account with user fields", function() {
|
||||||
|
|
||||||
click(".user-field input[type=checkbox]");
|
click(".user-field input[type=checkbox]");
|
||||||
andThen(function() {
|
andThen(function() {
|
||||||
not(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked');
|
not(exists('.modal-footer .btn-primary:disabled'), 'create account is enabled because field is not checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
click(".user-field input[type=checkbox]");
|
click(".user-field input[type=checkbox]");
|
||||||
|
|
Loading…
Reference in a new issue