Skip to content

Commit 8f518a2

Browse files
committed
Merge pull request discourse#604 from wpp/refactor_suggest_username
Improve suggest_username method in user class
2 parents b61907f + c34f476 commit 8f518a2

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

app/models/user.rb

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,31 +59,20 @@ def self.username_length
5959
3..15
6060
end
6161

62-
def self.suggest_username(name)
63-
return unless name.present?
64-
65-
# If it's an email
66-
if name =~ /([^@]+)@([^\.]+)/
67-
name = Regexp.last_match[1]
68-
69-
# Special case, if it's "me" or "i" @ something, take the something.
70-
name = Regexp.last_match[2] if ['i', 'me'].include?(name)
71-
end
72-
73-
name.gsub!(/^[^A-Za-z0-9]+/, "")
74-
name.gsub!(/[^A-Za-z0-9_]+$/, "")
62+
def self.sanitize_username!(name)
63+
name.gsub!(/^[^A-Za-z0-9]+|[^A-Za-z0-9_]+$/, "")
7564
name.gsub!(/[^A-Za-z0-9_]+/, "_")
65+
end
7666

77-
# Pad the length with 1s
67+
def self.pad_missing_chars_with_1s!(name)
7868
missing_chars = User.username_length.begin - name.length
7969
name << ('1' * missing_chars) if missing_chars > 0
70+
end
8071

81-
# Trim extra length
82-
name = name[0..User.username_length.end-1]
83-
72+
def self.find_available_username_based_on(name)
8473
i = 1
8574
attempt = name
86-
while !username_available?(attempt)
75+
until username_available?(attempt)
8776
suffix = i.to_s
8877
max_length = User.username_length.end - suffix.length - 1
8978
attempt = "#{name[0..max_length]}#{suffix}"
@@ -92,6 +81,27 @@ def self.suggest_username(name)
9281
attempt
9382
end
9483

84+
EMAIL = %r{([^@]+)@([^\.]+)}
85+
86+
def self.suggest_username(name)
87+
return unless name.present?
88+
89+
if name =~ EMAIL
90+
# When 'walter@white.com' take 'walter'
91+
name = Regexp.last_match[1]
92+
93+
# When 'me@eviltrout.com' take 'eviltrout'
94+
name = Regexp.last_match[2] if ['i', 'me'].include?(name)
95+
end
96+
97+
sanitize_username!(name)
98+
pad_missing_chars_with_1s!(name)
99+
100+
# Trim extra length
101+
name = name[0..User.username_length.end-1]
102+
find_available_username_based_on(name)
103+
end
104+
95105
def self.create_for_email(email, opts={})
96106
username = suggest_username(email)
97107

@@ -240,7 +250,7 @@ def self.mentionable_usernames
240250
end
241251

242252
def moderator?
243-
# this saves us from checking both, admins are always moderators
253+
# this saves us from checking both, admins are always moderators
244254
#
245255
# in future we may split this out
246256
admin || moderator
@@ -409,7 +419,7 @@ def has_trust_level?(level)
409419
end
410420

411421
# a touch faster than automatic
412-
def admin?
422+
def admin?
413423
admin
414424
end
415425

@@ -545,7 +555,7 @@ def email_validator
545555
end
546556
end
547557
end
548-
558+
549559
def email_in_restriction_setting?(setting)
550560
domains = setting.gsub('.', '\.')
551561
regexp = Regexp.new("@(#{domains})", true)

spec/models/user_spec.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@
443443
end
444444

445445
it 'corrects weird characters' do
446-
User.suggest_username("Darth%^Vadar").should == "Darth_Vadar"
446+
User.suggest_username("Darth%^Vader").should == "Darth_Vader"
447447
end
448448

449449
it 'adds 1 to an existing username' do
@@ -455,8 +455,9 @@
455455
User.suggest_username('a').should == 'a11'
456456
end
457457

458-
it "has a special case for me emails" do
458+
it "has a special case for me and i emails" do
459459
User.suggest_username('me@eviltrout.com').should == 'eviltrout'
460+
User.suggest_username('i@eviltrout.com').should == 'eviltrout'
460461
end
461462

462463
it "shortens very long suggestions" do
@@ -511,12 +512,12 @@
511512
Fabricate.build(:user, email: 'notgood@trashmail.net').should_not be_valid
512513
Fabricate.build(:user, email: 'mailinator.com@gmail.com').should be_valid
513514
end
514-
515+
515516
it 'should not reject partial matches' do
516517
SiteSetting.stubs(:email_domains_blacklist).returns('mail.com')
517518
Fabricate.build(:user, email: 'mailinator@gmail.com').should be_valid
518519
end
519-
520+
520521
it 'should reject some emails based on the email_domains_blacklist site setting ignoring case' do
521522
SiteSetting.stubs(:email_domains_blacklist).returns('trashmail.net')
522523
Fabricate.build(:user, email: 'notgood@TRASHMAIL.NET').should_not be_valid
@@ -539,7 +540,7 @@
539540
u.email = 'nope@mailinator.com'
540541
u.should_not be_valid
541542
end
542-
543+
543544
it 'whitelist should reject some emails based on the email_domains_whitelist site setting' do
544545
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com')
545546
Fabricate.build(:user, email: 'notgood@mailinator.com').should_not be_valid
@@ -565,7 +566,7 @@
565566
u.should be_valid
566567
end
567568

568-
it 'email whitelist should be used when email is being changed' do
569+
it 'email whitelist should be used when email is being changed' do
569570
SiteSetting.stubs(:email_domains_whitelist).returns('vaynermedia.com')
570571
u = Fabricate(:user, email: 'good@vaynermedia.com')
571572
u.email = 'nope@mailinator.com'
@@ -735,11 +736,12 @@
735736
end
736737

737738
describe '#create_for_email' do
738-
let(:subject) { User.create_for_email('test@email.com') }
739+
let(:subject) { User.create_for_email('walter.white@email.com') }
739740
it { should be_present }
740-
its(:username) { should == 'test' }
741-
its(:name) { should == 'test'}
741+
its(:username) { should == 'walter_white' }
742+
its(:name) { should == 'walter_white'}
742743
it { should_not be_active }
744+
its(:email) { should == 'walter.white@email.com' }
743745
end
744746

745747
describe 'email_confirmed?' do

0 commit comments

Comments
 (0)