FEATURE: custom fields on User
This commit is contained in:
parent
25860622b7
commit
a3b2b4baca
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)
|
||||
#
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue