2015-10-11 17:41:23 +08:00
require 'rails_helper'
2015-03-07 05:44:54 +08:00
describe UsernameChanger do
describe '#change' do
let ( :user ) { Fabricate ( :user ) }
context 'success' do
let ( :new_username ) { " #{ user . username } 1234 " }
2018-05-31 15:04:53 +08:00
it 'should change the username' do
2017-02-28 04:02:00 +08:00
@result = UsernameChanger . change ( user , new_username )
2015-03-07 05:44:54 +08:00
expect ( @result ) . to eq ( true )
user . reload
expect ( user . username ) . to eq ( new_username )
expect ( user . username_lower ) . to eq ( new_username . downcase )
end
end
context 'failure' do
let ( :wrong_username ) { " " }
let ( :username_before_change ) { user . username }
let ( :username_lower_before_change ) { user . username_lower }
2018-05-31 15:04:53 +08:00
it 'should not change the username' do
2017-02-28 04:02:00 +08:00
@result = UsernameChanger . change ( user , wrong_username )
2015-03-07 05:44:54 +08:00
expect ( @result ) . to eq ( false )
user . reload
expect ( user . username ) . to eq ( username_before_change )
expect ( user . username_lower ) . to eq ( username_lower_before_change )
end
end
describe 'change the case of my username' do
let! ( :myself ) { Fabricate ( :user , username : 'hansolo' ) }
it 'should change the username' do
2018-05-31 15:04:53 +08:00
expect do
expect ( UsernameChanger . change ( myself , " HanSolo " , myself ) ) . to eq ( true )
end . to change { UserHistory . count } . by ( 1 )
2015-03-07 05:44:54 +08:00
expect ( myself . reload . username ) . to eq ( 'HanSolo' )
2017-02-23 13:48:57 +08:00
2018-05-31 15:04:53 +08:00
expect do
UsernameChanger . change ( myself , " HanSolo " , myself )
end . to change { UserHistory . count } . by ( 0 ) # make sure it does not log a dupe
2017-02-23 13:48:57 +08:00
end
2015-03-07 05:44:54 +08:00
end
describe 'allow custom minimum username length from site settings' do
before do
@custom_min = 2
SiteSetting . min_username_length = @custom_min
end
it 'should allow a shorter username than default' do
2017-02-28 04:02:00 +08:00
result = UsernameChanger . change ( user , 'a' * @custom_min )
2015-03-07 05:44:54 +08:00
expect ( result ) . not_to eq ( false )
end
it 'should not allow a shorter username than limit' do
2017-02-28 04:02:00 +08:00
result = UsernameChanger . change ( user , 'a' * ( @custom_min - 1 ) )
2015-03-07 05:44:54 +08:00
expect ( result ) . to eq ( false )
end
it 'should not allow a longer username than limit' do
2017-02-28 04:02:00 +08:00
result = UsernameChanger . change ( user , 'a' * ( User . username_length . end + 1 ) )
2015-03-07 05:44:54 +08:00
expect ( result ) . to eq ( false )
end
end
2018-05-01 07:54:36 +08:00
context 'posts and revisions' do
let ( :user ) { Fabricate ( :user , username : 'foo' ) }
let ( :topic ) { Fabricate ( :topic , user : user ) }
2018-05-16 03:05:51 +08:00
before do
UserActionCreator . enable
Discourse . expects ( :warn_exception ) . never
end
after do
UserActionCreator . disable
end
2018-05-01 07:54:36 +08:00
2018-05-08 22:02:43 +08:00
def create_post_and_change_username ( args = { } , & block )
2018-05-01 07:54:36 +08:00
post = create_post ( args . merge ( topic_id : topic . id ) )
args . delete ( :revisions ) & . each do | revision |
post . revise ( post . user , revision , force_new_version : true )
end
2018-05-08 22:02:43 +08:00
block . call ( post ) if block
2018-05-01 07:54:36 +08:00
UsernameChanger . change ( user , 'bar' )
post . reload
end
context 'mentions' do
it 'rewrites cooked correctly' do
post = create_post_and_change_username ( raw : " Hello @foo " )
expect ( post . cooked ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a></p> ) )
post . rebake!
expect ( post . cooked ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a></p> ) )
end
2018-05-14 19:20:15 +08:00
it 'removes the username from the search index' do
SearchIndexer . enable
create_post_and_change_username ( raw : " Hello @foo " )
results = Search . execute ( 'foo' , min_search_term_length : 1 )
expect ( results . posts ) . to be_empty
end
2018-05-01 07:54:36 +08:00
it 'ignores case when replacing mentions' do
post = create_post_and_change_username ( raw : " There's no difference between @foo and @Foo " )
expect ( post . raw ) . to eq ( " There's no difference between @bar and @bar " )
expect ( post . cooked ) . to eq ( %Q( <p>There’ s no difference between <a class="mention" href="/u/bar">@bar</a> and <a class="mention" href="/u/bar">@bar</a></p> ) )
end
it 'replaces mentions when there are leading symbols' do
post = create_post_and_change_username ( raw : " .@foo -@foo %@foo _@foo ,@foo ;@foo @@foo " )
expect ( post . raw ) . to eq ( " .@bar -@bar %@bar _@bar ,@bar ;@bar @@bar " )
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > . < a class = " mention " href = " /u/bar " > @bar < / a>
- < a class = " mention " href = " /u/bar " > @bar < / a>
%< a class="mention" href="/u/bar" > @bar < / a>
_ < a class = " mention " href = " /u/bar " > @bar < / a>
, < a class = " mention " href = " /u/bar " > @bar < / a>
; < a class = " mention " href = " /u/bar " > @bar < / a>
@ < a class = " mention " href = " /u/bar " > @bar < / a>< / p >
HTML
end
it 'replaces mentions within double and single quotes' do
post = create_post_and_change_username ( raw : %Q( "@foo" '@foo' ) )
expect ( post . raw ) . to eq ( %Q( "@bar" '@bar' ) )
expect ( post . cooked ) . to eq ( %Q( <p>“<a class="mention" href="/u/bar">@bar</a>” ‘ <a class="mention" href="/u/bar">@bar</a>’ </p> ) )
end
it 'replaces mentions when there are trailing symbols' do
post = create_post_and_change_username ( raw : " @foo. @foo, @foo: @foo; @foo- " )
expect ( post . raw ) . to eq ( " @bar. @bar, @bar: @bar; @bar- " )
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > < a class = " mention " href = " /u/bar " > @bar < / a>.
< a class = " mention " href = " /u/bar " > @bar < / a>,
< a class = " mention " href = " /u/bar " > @bar < / a>:
< a class = " mention " href = " /u/bar " > @bar < / a>;
< a class = " mention " href = " /u/bar " > @bar < / a>-< / p >
HTML
end
it 'does not replace mention when followed by an underscore' do
post = create_post_and_change_username ( raw : " @foo_ " )
expect ( post . raw ) . to eq ( " @foo_ " )
expect ( post . cooked ) . to eq ( %Q( <p><span class="mention">@foo_</span></p> ) )
end
it 'does not replace mentions when there are leading alphanumeric chars' do
post = create_post_and_change_username ( raw : " a@foo 2@foo " )
expect ( post . raw ) . to eq ( " a@foo 2@foo " )
expect ( post . cooked ) . to eq ( %Q( <p>a@foo 2@foo</p> ) )
end
it 'does not replace username within email address' do
post = create_post_and_change_username ( raw : " mail@foo.com " )
expect ( post . raw ) . to eq ( " mail@foo.com " )
expect ( post . cooked ) . to eq ( %Q( <p><a href="mailto:mail@foo.com">mail@foo.com</a></p> ) )
end
it 'does not replace username in a mention of a similar username' do
Fabricate ( :user , username : 'foobar' )
Fabricate ( :user , username : 'foo-bar' )
Fabricate ( :user , username : 'foo_bar' )
Fabricate ( :user , username : 'foo1' )
post = create_post_and_change_username ( raw : " @foo @foobar @foo-bar @foo_bar @foo1 " )
expect ( post . raw ) . to eq ( " @bar @foobar @foo-bar @foo_bar @foo1 " )
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > < a class = " mention " href = " /u/bar " > @bar < / a>
< a class = " mention " href = " /u/foobar " > @foobar < / a>
< a class = " mention " href = " /u/foo-bar " > @foo - bar < / a>
< a class = " mention " href = " /u/foo_bar " > @foo_bar < / a>
< a class = " mention " href = " /u/foo1 " > @foo1 < / a>< / p >
HTML
end
it 'updates the path to the user even when it links to /user instead of /u' do
post = create_post_and_change_username ( raw : " Hello @foo " )
post . update_column ( :cooked , post . cooked . gsub ( " /u/foo " , " /users/foo " ) )
expect ( post . raw ) . to eq ( " Hello @bar " )
expect ( post . cooked ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a></p> ) )
end
it 'replaces mentions within revisions' do
2018-05-14 20:47:47 +08:00
revisions = [ { raw : " Hello Foo " } , { title : " new topic title " } , { raw : " Hello @foo! " } , { raw : " Hello @foo!! " } ]
2018-05-01 07:54:36 +08:00
post = create_post_and_change_username ( raw : " Hello @foo " , revisions : revisions )
expect ( post . raw ) . to eq ( " Hello @bar!! " )
expect ( post . cooked ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a>!!</p> ) )
2018-05-14 20:47:47 +08:00
expect ( post . revisions . count ) . to eq ( 4 )
2018-05-01 07:54:36 +08:00
expect ( post . revisions [ 0 ] . modifications [ " raw " ] [ 0 ] ) . to eq ( " Hello @bar " )
expect ( post . revisions [ 0 ] . modifications [ " raw " ] [ 1 ] ) . to eq ( " Hello Foo " )
expect ( post . revisions [ 0 ] . modifications [ " cooked " ] [ 0 ] ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a></p> ) )
expect ( post . revisions [ 0 ] . modifications [ " cooked " ] [ 1 ] ) . to eq ( %Q( <p>Hello Foo</p> ) )
2018-05-14 20:47:47 +08:00
expect ( post . revisions [ 1 ] . modifications ) . to include ( " title " )
2018-05-01 07:54:36 +08:00
2018-05-14 20:47:47 +08:00
expect ( post . revisions [ 2 ] . modifications [ " raw " ] [ 0 ] ) . to eq ( " Hello Foo " )
expect ( post . revisions [ 2 ] . modifications [ " raw " ] [ 1 ] ) . to eq ( " Hello @bar! " )
expect ( post . revisions [ 2 ] . modifications [ " cooked " ] [ 0 ] ) . to eq ( %Q( <p>Hello Foo</p> ) )
expect ( post . revisions [ 2 ] . modifications [ " cooked " ] [ 1 ] ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a>!</p> ) )
expect ( post . revisions [ 3 ] . modifications [ " raw " ] [ 0 ] ) . to eq ( " Hello @bar! " )
expect ( post . revisions [ 3 ] . modifications [ " raw " ] [ 1 ] ) . to eq ( " Hello @bar!! " )
expect ( post . revisions [ 3 ] . modifications [ " cooked " ] [ 0 ] ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a>!</p> ) )
expect ( post . revisions [ 3 ] . modifications [ " cooked " ] [ 1 ] ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a>!!</p> ) )
2018-05-01 07:54:36 +08:00
end
2018-05-08 22:02:43 +08:00
it 'replaces mentions in posts marked for deletion' do
post = create_post_and_change_username ( raw : " Hello @foo " ) do | p |
PostDestroyer . new ( p . user , p ) . destroy
end
expect ( post . raw ) . to_not include ( " @foo " )
expect ( post . cooked ) . to_not include ( " foo " )
expect ( post . revisions . count ) . to eq ( 1 )
expect ( post . revisions [ 0 ] . modifications [ " raw " ] [ 0 ] ) . to eq ( " Hello @bar " )
expect ( post . revisions [ 0 ] . modifications [ " cooked " ] [ 0 ] ) . to eq ( %Q( <p>Hello <a class="mention" href="/u/bar">@bar</a></p> ) )
end
2018-05-16 03:05:51 +08:00
it 'works when users are mentioned with HTML' do
post = create_post_and_change_username ( raw : '<a class="mention">@foo</a> and <a class="mention">@someuser</a>' )
expect ( post . raw ) . to eq ( '<a class="mention">@bar</a> and <a class="mention">@someuser</a>' )
expect ( post . cooked ) . to match_html ( '<p><a class="mention">@bar</a> and <a class="mention">@someuser</a></p>' )
end
2018-05-01 07:54:36 +08:00
end
context 'quotes' do
let ( :quoted_post ) { create_post ( user : user , topic : topic , post_number : 1 , raw : " quoted post " ) }
2018-05-08 22:02:43 +08:00
let ( :avatar_url ) { user . avatar_template . gsub ( " {size} " , " 40 " ) }
2018-05-01 07:54:36 +08:00
2018-05-14 19:15:31 +08:00
it 'replaces the username in quote tags and updates avatar' do
2018-05-01 07:54:36 +08:00
post = create_post_and_change_username ( raw : << ~ RAW )
Lorem ipsum
[ quote = " foo, post:1, topic: #{ quoted_post . topic . id } " ]
quoted post
[ / quote]
[ quote = 'foo' ]
quoted post
[ / quote]
[ quote = foo , post : 1 , topic : #{quoted_post.topic.id}]
quoted post
[ / quote]
dolor sit amet
RAW
expect ( post . raw ) . to eq ( << ~ RAW . strip )
Lorem ipsum
[ quote = " bar, post:1, topic: #{ quoted_post . topic . id } " ]
quoted post
[ / quote]
[ quote = 'bar' ]
quoted post
[ / quote]
[ quote = bar , post : 1 , topic : #{quoted_post.topic.id}]
quoted post
[ / quote]
dolor sit amet
RAW
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > Lorem ipsum < / p>
< aside class = " quote no-group " data - post = " 1 " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
2018-05-08 22:02:43 +08:00
< img alt = '' width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " > bar : < / div>
2018-05-01 07:54:36 +08:00
< blockquote >
< p > quoted post < / p>
< / blockquote>
< / aside>
< aside class = " quote no-group " >
< div class = " title " >
< div class = " quote-controls " > < / div>
2018-05-08 22:02:43 +08:00
< img alt = '' width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " > bar : < / div>
2018-05-01 07:54:36 +08:00
< blockquote >
< p > quoted post < / p>
< / blockquote>
< / aside>
< aside class = " quote no-group " data - post = " 1 " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
2018-05-08 22:02:43 +08:00
< img alt = '' width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " > bar : < / div>
2018-05-01 07:54:36 +08:00
< blockquote >
< p > quoted post < / p>
< / blockquote>
< / aside>
< p > dolor sit amet < / p>
HTML
end
2018-05-08 22:02:43 +08:00
context 'simple quote' do
let ( :raw ) do << ~ RAW
Lorem ipsum
[ quote = " foo, post:1, topic: #{ quoted_post . topic . id } " ]
quoted post
[ / quote]
RAW
end
let ( :expected_raw ) do
<< ~ RAW . strip
Lorem ipsum
[ quote = " bar, post:1, topic: #{ quoted_post . topic . id } " ]
quoted post
[ / quote]
RAW
end
let ( :expected_cooked ) do
<< ~ HTML
< p > Lorem ipsum < / p>
< aside class = " quote no-group " data - post = " 1 " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
< img alt = '' width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " > bar : < / div>
< blockquote >
< p > quoted post < / p>
< / blockquote>
< / aside>
HTML
end
it 'replaces the username in quote tags when the post is deleted' do
post = create_post_and_change_username ( raw : raw ) do | p |
PostDestroyer . new ( Discourse . system_user , p ) . destroy
end
expect ( post . raw ) . to eq ( expected_raw )
expect ( post . cooked ) . to match_html ( expected_cooked )
end
end
2018-05-14 19:15:31 +08:00
end
context 'oneboxes' do
let ( :quoted_post ) { create_post ( user : user , topic : topic , post_number : 1 , raw : " quoted post " ) }
2018-05-22 19:41:32 +08:00
let ( :avatar_url ) { user_avatar_url ( user ) }
let ( :evil_trout ) { Fabricate ( :evil_trout ) }
let ( :another_quoted_post ) { create_post ( user : evil_trout , topic : topic , post_number : 2 , raw : " evil post " ) }
2018-05-14 19:15:31 +08:00
def protocol_relative_url ( url )
url . sub ( / ^https?: / , '' )
end
2018-05-22 19:41:32 +08:00
def user_avatar_url ( u )
u . avatar_template . gsub ( " {size} " , " 40 " )
end
2018-05-14 19:15:31 +08:00
it 'updates avatar for linked topics and posts' do
raw = " #{ quoted_post . full_url } \n #{ quoted_post . topic . url } "
post = create_post_and_change_username ( raw : raw )
expect ( post . raw ) . to eq ( raw )
2018-05-08 22:02:43 +08:00
2018-05-14 19:15:31 +08:00
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > < aside class = " quote " data - post = " #{ quoted_post . post_number } " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
< img alt = " " width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " >
< a href = " #{ protocol_relative_url ( quoted_post . full_url ) } " > #{quoted_post.topic.title}</a>
< / div>
< blockquote >
quoted post
< / blockquote>
< / aside>
< br >
< aside class = " quote " data - post = " #{ quoted_post . post_number } " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
< img alt = " " width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " >
< a href = " #{ protocol_relative_url ( quoted_post . topic . url ) } " > #{quoted_post.topic.title}</a>
< / div>
< blockquote >
quoted post
< / blockquote>
< / aside>
< / p>
HTML
end
2018-05-22 19:41:32 +08:00
it 'does not update the wrong avatar' do
raw = " #{ quoted_post . full_url } \n #{ another_quoted_post . full_url } "
post = create_post_and_change_username ( raw : raw )
expect ( post . raw ) . to eq ( raw )
expect ( post . cooked ) . to match_html ( << ~ HTML )
< p > < aside class = " quote " data - post = " #{ quoted_post . post_number } " data - topic = " #{ quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
< img alt = " " width = " 20 " height = " 20 " src = " #{ avatar_url } " class = " avatar " >
< a href = " #{ protocol_relative_url ( quoted_post . full_url ) } " > #{quoted_post.topic.title}</a>
< / div>
< blockquote >
quoted post
< / blockquote>
< / aside>
< br >
< aside class = " quote " data - post = " #{ another_quoted_post . post_number } " data - topic = " #{ another_quoted_post . topic . id } " >
< div class = " title " >
< div class = " quote-controls " > < / div>
< img alt = " " width = " 20 " height = " 20 " src = " #{ user_avatar_url ( evil_trout ) } " class = " avatar " >
< a href = " #{ protocol_relative_url ( another_quoted_post . full_url ) } " > #{another_quoted_post.topic.title}</a>
< / div>
< blockquote >
evil post
< / blockquote>
< / aside>
< / p>
HTML
end
2018-05-01 07:54:36 +08:00
end
2018-05-16 03:05:51 +08:00
it 'updates username in small action posts' do
invited_by = Fabricate ( :user )
p1 = topic . add_small_action ( invited_by , 'invited_user' , 'foo' )
p2 = topic . add_small_action ( invited_by , 'invited_user' , 'foobar' )
UsernameChanger . change ( user , 'bar' )
expect ( p1 . reload . custom_fields [ 'action_code_who' ] ) . to eq ( 'bar' )
expect ( p2 . reload . custom_fields [ 'action_code_who' ] ) . to eq ( 'foobar' )
end
2018-05-01 07:54:36 +08:00
end
2018-05-08 22:02:43 +08:00
context 'notifications' do
def create_notification ( type , notified_user , post , data = { } )
Fabricate (
:notification ,
notification_type : Notification . types [ type ] ,
user : notified_user ,
data : data . to_json ,
topic : post & . topic ,
post_number : post & . post_number
)
end
def notification_data ( notification )
JSON . parse ( notification . reload . data , symbolize_names : true )
end
def original_and_display_username ( username )
{ original_username : username , display_username : username , foo : " bar " }
end
def original_username_and_some_text_as_display_username ( username )
{ original_username : username , display_username : " some text " , foo : " bar " }
end
def only_display_username ( username )
{ display_username : username }
end
def username_and_something_else ( username )
{ username : username , foo : " bar " }
end
it 'replaces usernames in notifications' do
renamed_user = Fabricate ( :user , username : " alice " )
another_user = Fabricate ( :user , username : " another_user " )
notified_user = Fabricate ( :user )
p1 = Fabricate ( :post , post_number : 1 , user : renamed_user )
p2 = Fabricate ( :post , post_number : 1 , user : another_user )
Fabricate ( :invite , invited_by : notified_user , user : renamed_user )
Fabricate ( :invite , invited_by : notified_user , user : another_user )
n01 = create_notification ( :mentioned , notified_user , p1 , original_and_display_username ( " alice " ) )
n02 = create_notification ( :mentioned , notified_user , p2 , original_and_display_username ( " another_user " ) )
n03 = create_notification ( :mentioned , notified_user , p1 , original_username_and_some_text_as_display_username ( " alice " ) )
n04 = create_notification ( :mentioned , notified_user , p1 , only_display_username ( " alice " ) )
n05 = create_notification ( :invitee_accepted , notified_user , nil , only_display_username ( " alice " ) )
n06 = create_notification ( :invitee_accepted , notified_user , nil , only_display_username ( " another_user " ) )
n07 = create_notification ( :granted_badge , renamed_user , nil , username_and_something_else ( " alice " ) )
n08 = create_notification ( :granted_badge , another_user , nil , username_and_something_else ( " another_user " ) )
n09 = create_notification ( :group_message_summary , renamed_user , nil , username_and_something_else ( " alice " ) )
n10 = create_notification ( :group_message_summary , another_user , nil , username_and_something_else ( " another_user " ) )
UsernameChanger . change ( renamed_user , " bob " )
expect ( notification_data ( n01 ) ) . to eq ( original_and_display_username ( " bob " ) )
expect ( notification_data ( n02 ) ) . to eq ( original_and_display_username ( " another_user " ) )
expect ( notification_data ( n03 ) ) . to eq ( original_username_and_some_text_as_display_username ( " bob " ) )
expect ( notification_data ( n04 ) ) . to eq ( only_display_username ( " bob " ) )
expect ( notification_data ( n05 ) ) . to eq ( only_display_username ( " bob " ) )
expect ( notification_data ( n06 ) ) . to eq ( only_display_username ( " another_user " ) )
expect ( notification_data ( n07 ) ) . to eq ( username_and_something_else ( " bob " ) )
expect ( notification_data ( n08 ) ) . to eq ( username_and_something_else ( " another_user " ) )
expect ( notification_data ( n09 ) ) . to eq ( username_and_something_else ( " bob " ) )
expect ( notification_data ( n10 ) ) . to eq ( username_and_something_else ( " another_user " ) )
end
end
2015-03-07 05:44:54 +08:00
end
end