FEATURE: custom fields on User

This commit is contained in:
Sam 2014-04-22 13:52:13 +10:00
parent 25860622b7
commit a3b2b4baca
9 changed files with 139 additions and 15 deletions

View File

@ -8,10 +8,10 @@ end
#
# Table name: badge_types
#
# id :integer not null, primary key
# name :string(255) not null
# created_at :datetime
# updated_at :datetime
# id :integer not null, primary key
# name :string(255) not null
# created_at :datetime
# updated_at :datetime
#
# Indexes
#

View File

@ -60,6 +60,10 @@ class DiscourseSingleSignOn < SingleSignOn
user.enqueue_welcome_message('welcome_user')
end
custom_fields.each do |k,v|
user.custom_fields[k] = v
end
# optionally save the user and sso_record if they have changed
user.save!
sso_record.save!

View File

@ -32,6 +32,7 @@ class User < ActiveRecord::Base
has_many :invites, dependent: :destroy
has_many :topic_links, dependent: :destroy
has_many :uploads
has_many :user_custom_fields, dependent: :destroy
has_one :facebook_user_info, dependent: :destroy
has_one :twitter_user_info, dependent: :destroy
@ -68,6 +69,7 @@ class User < ActiveRecord::Base
after_save :update_tracked_topics
after_save :clear_global_notice_if_needed
after_save :save_custom_fields
after_create :create_email_token
after_create :create_user_stat
@ -587,8 +589,35 @@ class User < ActiveRecord::Base
nil
end
def custom_fields
@custom_fields ||= begin
@custom_fields_orig = Hash[*user_custom_fields.pluck(:name,:value).flatten]
@custom_fields_orig.dup
end
end
protected
def save_custom_fields
if @custom_fields && @custom_fields_orig != @custom_fields
dup = @custom_fields.dup
user_custom_fields.each do |f|
if dup[f.name] != f.value
f.destroy
else
dup.remove[f.name]
end
end
dup.each do |k,v|
user_custom_fields.create(name: k, value: v)
end
@custom_fields_orig = @custom_fields
end
end
def cook
if bio_raw.present?
self.bio_cooked = PrettyText.cook(bio_raw, omit_nofollow: self.has_trust_level?(:leader)) if bio_raw_changed?

View File

@ -0,0 +1,19 @@
class UserCustomField < ActiveRecord::Base
belongs_to :user
end
# == Schema Information
#
# Table name: user_custom_fields
#
# id :integer not null, primary key
# user_id :integer not null
# name :string(256) not null
# value :text
# created_at :datetime
# updated_at :datetime
#
# Indexes
#
# index_user_custom_fields_on_user_id_and_name (user_id,name)
#

View File

@ -0,0 +1,12 @@
class AddUserCustomFields < ActiveRecord::Migration
def change
create_table :user_custom_fields do |t|
t.integer :user_id, null: false
t.string :name, limit: 256, null: false
t.text :value
t.timestamps
end
add_index :user_custom_fields, [:user_id, :name]
end
end

View File

@ -1,5 +1,7 @@
class SingleSignOn
ACCESSORS = [:nonce, :name, :username, :email, :about_me, :external_email, :external_username, :external_name, :external_id]
ACCESSORS = [:nonce, :name, :username, :email,
:about_me, :external_email, :external_username,
:external_name, :external_id]
FIXNUMS = []
NONCE_EXPIRY_TIME = 10.minutes
@ -14,14 +16,6 @@ class SingleSignOn
raise RuntimeError, "sso_url not implemented on class, be sure to set it on instance"
end
def sso_secret
@sso_secret || self.class.sso_secret
end
def sso_url
@sso_url || self.class.sso_url
end
def self.parse(payload, sso_secret = nil)
sso = new
sso.sso_secret = sso_secret if sso_secret
@ -39,9 +33,33 @@ class SingleSignOn
val = val.to_i if FIXNUMS.include? k
sso.send("#{k}=", val)
end
decoded_hash.each do |k,v|
# 1234567
# custom.
#
if k[0..6] == "custom."
field = k[7..-1]
sso.custom_fields[field] = v
end
end
sso
end
def sso_secret
@sso_secret || self.class.sso_secret
end
def sso_url
@sso_url || self.class.sso_url
end
def custom_fields
@custom_fields ||= {}
end
def sign(payload)
OpenSSL::HMAC.hexdigest("sha256", sso_secret, payload)
end
@ -65,6 +83,12 @@ class SingleSignOn
payload[k] = val
end
if @custom_fields
@custom_fields.each do |k,v|
payload["custom.#{k}"] = v.to_s
end
end
Rack::Utils.build_query(payload)
end

View File

@ -43,7 +43,6 @@ describe SessionController do
response.should redirect_to('/')
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
logged_on_user.email.should == user.email
logged_on_user.single_sign_on_record.external_id.should == "abc"
logged_on_user.single_sign_on_record.external_username.should == 'sam'
end
@ -54,12 +53,17 @@ describe SessionController do
sso.email = 'bob@bob.com'
sso.name = 'Sam Saffron'
sso.username = 'sam'
sso.custom_fields["shop_url"] = "http://my_shop.com"
sso.custom_fields["shop_name"] = "Sam"
get :sso_login, Rack::Utils.parse_query(sso.payload)
response.should redirect_to('/a/')
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
# ensure nothing is transient
logged_on_user = User.find(logged_on_user.id)
logged_on_user.email.should == 'bob@bob.com'
logged_on_user.name.should == 'Sam Saffron'
logged_on_user.username.should == 'sam'
@ -67,8 +71,11 @@ describe SessionController do
logged_on_user.single_sign_on_record.external_id.should == "666"
logged_on_user.single_sign_on_record.external_username.should == 'sam'
logged_on_user.active.should == true
logged_on_user.custom_fields["shop_url"].should == "http://my_shop.com"
logged_on_user.custom_fields["shop_name"].should == "Sam"
logged_on_user.custom_fields["bla"].should == nil
end
it 'allows login to existing account with valid nonce' do
sso = get_sso('/hello/world')
sso.external_id = '997'

View File

@ -19,6 +19,8 @@ describe DiscourseSingleSignOn do
sso.username = "sam"
sso.name = "sam saffron"
sso.external_id = "100"
sso.custom_fields["a"] = "Aa"
sso.custom_fields["b.b"] = "B.b"
sso
end
@ -28,6 +30,8 @@ describe DiscourseSingleSignOn do
parsed.username.should == sso.username
parsed.name.should == sso.name
parsed.external_id.should == sso.external_id
parsed.custom_fields["a"].should == "Aa"
parsed.custom_fields["b.b"].should == "B.b"
end
it "can fill in data on way back" do

View File

@ -1149,4 +1149,29 @@ describe User do
end
describe "custom fields" do
it "allows modification of custom fields" do
user = Fabricate(:user)
user.custom_fields["a"].should == nil
user.custom_fields["bob"] = "marley"
user.custom_fields["jack"] = "black"
user.save
user = User.find(user.id)
user.custom_fields["bob"].should == "marley"
user.custom_fields["jack"].should == "black"
user.custom_fields.delete("bob")
user.custom_fields["jack"] = "jill"
user.save
user = User.find(user.id)
user.custom_fields.should == {"jack" => "jill"}
end
end
end