FEATURE: allow shipping bio markdown via SSO

- Also adds site setting for sso_overrides_bio to disable bio editing by end users
This commit is contained in:
Sam 2016-08-01 15:29:28 +10:00
parent e79c216bc0
commit 9018de39ed
10 changed files with 78 additions and 7 deletions

View file

@ -48,6 +48,12 @@ export default Ember.Controller.extend(CanCheckEmails, {
return this.siteSettings.enable_badges && hasTitleBadges; return this.siteSettings.enable_badges && hasTitleBadges;
}, },
@computed("model.can_change_bio")
canChangeBio(canChangeBio)
{
return canChangeBio;
},
@computed() @computed()
canChangePassword() { canChangePassword() {
return !this.siteSettings.enable_sso && this.siteSettings.enable_local_logins; return !this.siteSettings.enable_sso && this.siteSettings.enable_local_logins;

View file

@ -130,12 +130,14 @@
</div> </div>
{{/if}} {{/if}}
{{#if canChangeBio}}
<div class="control-group pref-bio"> <div class="control-group pref-bio">
<label class="control-label">{{i18n 'user.bio'}}</label> <label class="control-label">{{i18n 'user.bio'}}</label>
<div class="controls bio-composer"> <div class="controls bio-composer">
{{d-editor value=model.bio_raw}} {{d-editor value=model.bio_raw}}
</div> </div>
</div> </div>
{{/if}}
{{#each userFields as |uf|}} {{#each userFields as |uf|}}
{{user-field field=uf.field value=uf.value}} {{user-field field=uf.field value=uf.value}}

View file

@ -82,6 +82,11 @@ class DiscourseSingleSignOn < SingleSignOn
# optionally save the user and sso_record if they have changed # optionally save the user and sso_record if they have changed
user.save! user.save!
if bio && (user.user_profile.bio_raw.blank? || SiteSetting.sso_overrides_bio)
user.user_profile.bio_raw = bio
user.user_profile.save!
end
unless admin.nil? && moderator.nil? unless admin.nil? && moderator.nil?
Group.refresh_automatic_groups!(:admins, :moderators, :staff) Group.refresh_automatic_groups!(:admins, :moderators, :staff)
end end

View file

@ -101,7 +101,8 @@ class UserSerializer < BasicUserSerializer
:card_image_badge, :card_image_badge,
:card_image_badge_id, :card_image_badge_id,
:muted_usernames, :muted_usernames,
:mailing_list_posts_per_day :mailing_list_posts_per_day,
:can_change_bio
untrusted_attributes :bio_raw, untrusted_attributes :bio_raw,
:bio_cooked, :bio_cooked,
@ -132,6 +133,10 @@ class UserSerializer < BasicUserSerializer
object.id && object.id == scope.user.try(:id) object.id && object.id == scope.user.try(:id)
end end
def can_change_bio
!(SiteSetting.enable_sso && SiteSetting.sso_overrides_bio)
end
def card_badge def card_badge
object.user_profile.card_image_badge object.user_profile.card_image_badge
end end

View file

@ -45,7 +45,9 @@ class UserUpdater
user_profile.location = attributes.fetch(:location) { user_profile.location } user_profile.location = attributes.fetch(:location) { user_profile.location }
user_profile.dismissed_banner_key = attributes[:dismissed_banner_key] if attributes[:dismissed_banner_key].present? user_profile.dismissed_banner_key = attributes[:dismissed_banner_key] if attributes[:dismissed_banner_key].present?
user_profile.website = format_url(attributes.fetch(:website) { user_profile.website }) user_profile.website = format_url(attributes.fetch(:website) { user_profile.website })
unless SiteSetting.enable_sso && SiteSetting.sso_overrides_bio
user_profile.bio_raw = attributes.fetch(:bio_raw) { user_profile.bio_raw } user_profile.bio_raw = attributes.fetch(:bio_raw) { user_profile.bio_raw }
end
user_profile.profile_background = attributes.fetch(:profile_background) { user_profile.profile_background } user_profile.profile_background = attributes.fetch(:profile_background) { user_profile.profile_background }
user_profile.card_background = attributes.fetch(:card_background) { user_profile.card_background } user_profile.card_background = attributes.fetch(:card_background) { user_profile.card_background }

View file

@ -977,6 +977,7 @@ en:
enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set" enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set"
sso_url: "URL of single sign on endpoint (must include http:// or https://)" sso_url: "URL of single sign on endpoint (must include http:// or https://)"
sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer"
sso_overrides_bio: "Overrides user bio in user profile and prevents user from changing it"
sso_overrides_email: "Overrides local email with external site email from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to normalization of local emails)" sso_overrides_email: "Overrides local email with external site email from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to normalization of local emails)"
sso_overrides_username: "Overrides local username with external site username from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to differences in username length/requirements)" sso_overrides_username: "Overrides local username with external site username from SSO payload on every login, and prevent local changes. (WARNING: discrepancies can occur due to differences in username length/requirements)"
sso_overrides_name: "Overrides local full name with external site full name from SSO payload on every login, and prevent local changes." sso_overrides_name: "Overrides local full name with external site full name from SSO payload on every login, and prevent local changes."

View file

@ -288,6 +288,7 @@ login:
default: '' default: ''
regex: '^https?:\/\/.+[^\/]$' regex: '^https?:\/\/.+[^\/]$'
sso_secret: '' sso_secret: ''
sso_overrides_bio: false
sso_overrides_email: false sso_overrides_email: false
sso_overrides_username: false sso_overrides_username: false
sso_overrides_name: false sso_overrides_name: false

View file

@ -1,6 +1,6 @@
class SingleSignOn class SingleSignOn
ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :require_activation, ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, :require_activation,
:about_me, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message] :bio, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message]
FIXNUMS = [] FIXNUMS = []
BOOLS = [:avatar_force_update, :admin, :moderator, :require_activation, :suppress_welcome_message] BOOLS = [:avatar_force_update, :admin, :moderator, :require_activation, :suppress_welcome_message]
NONCE_EXPIRY_TIME = 10.minutes NONCE_EXPIRY_TIME = 10.minutes

View file

@ -222,6 +222,47 @@ describe DiscourseSingleSignOn do
end end
end end
context 'setting bio for a user' do
let(:sso) {
sso = DiscourseSingleSignOn.new
sso.username = "test"
sso.name = "test"
sso.email = "test@test.com"
sso.external_id = "100"
sso.bio = "This **is** the bio"
sso
}
it 'can set bio if supplied on new users or users with empty bio' do
# new account
user = sso.lookup_or_create_user(ip_address)
expect(user.user_profile.bio_cooked).to match_html("<p>This <strong>is</strong> the bio</p>")
# no override by default
sso.bio = "new profile"
user = sso.lookup_or_create_user(ip_address)
expect(user.user_profile.bio_cooked).to match_html("<p>This <strong>is</strong> the bio</p>")
# yes override for blank
user.user_profile.bio_raw = " "
user.user_profile.save!
user = sso.lookup_or_create_user(ip_address)
expect(user.user_profile.bio_cooked).to match_html("<p>new profile</p>")
# yes override if site setting
sso.bio = "new profile 2"
SiteSetting.sso_overrides_bio = true
user = sso.lookup_or_create_user(ip_address)
expect(user.user_profile.bio_cooked).to match_html("<p>new profile 2</p>")
end
end
context 'when sso_overrides_avatar is enabled' do context 'when sso_overrides_avatar is enabled' do
let!(:sso_record) { Fabricate(:single_sign_on_record, external_avatar_url: "http://example.com/an_image.png") } let!(:sso_record) { Fabricate(:single_sign_on_record, external_avatar_url: "http://example.com/an_image.png") }
let!(:sso) { let!(:sso) {

View file

@ -65,7 +65,7 @@ describe UserUpdater do
user = Fabricate(:user) user = Fabricate(:user)
updater = UserUpdater.new(acting_user, user) updater = UserUpdater.new(acting_user, user)
updater.update(bio_raw: 'my new bio', val = updater.update(bio_raw: 'my new bio',
email_always: 'true', email_always: 'true',
mailing_list_mode: true, mailing_list_mode: true,
digest_after_minutes: "45", digest_after_minutes: "45",
@ -73,6 +73,8 @@ describe UserUpdater do
auto_track_topics_after_msecs: 101, auto_track_topics_after_msecs: 101,
email_in_reply_to: false email_in_reply_to: false
) )
expect(val).to be_truthy
user.reload user.reload
expect(user.user_profile.bio_raw).to eq 'my new bio' expect(user.user_profile.bio_raw).to eq 'my new bio'
@ -84,12 +86,18 @@ describe UserUpdater do
expect(user.user_option.email_in_reply_to).to eq false expect(user.user_option.email_in_reply_to).to eq false
end end
context 'when update succeeds' do context 'when sso overrides bio' do
it 'returns true' do it 'does not change bio' do
SiteSetting.enable_sso = true
SiteSetting.sso_overrides_bio = true
user = Fabricate(:user) user = Fabricate(:user)
updater = UserUpdater.new(acting_user, user) updater = UserUpdater.new(acting_user, user)
expect(updater.update).to be_truthy expect(updater.update(bio_raw: "new bio")).to be_truthy
user.reload
expect(user.user_profile.bio_raw).not_to eq 'new bio'
end end
end end