2019-04-29 20:27:42 -04:00
# frozen_string_literal: true
2022-07-27 22:27:38 -04:00
RSpec . describe Post do
2023-12-13 04:18:42 -05:00
fab! ( :coding_horror ) { Fabricate ( :coding_horror , refresh_auto_groups : true ) }
2021-12-15 12:41:14 -05:00
2023-01-18 11:40:21 -05:00
let ( :upload_path ) { Discourse . store . upload_path }
2013-06-19 03:19:42 -04:00
before { Oneboxer . stubs :onebox }
2023-06-05 11:38:50 -04:00
it_behaves_like " it has custom fields "
2023-01-18 11:40:21 -05:00
it { is_expected . to have_many ( :reviewables ) . dependent ( :destroy ) }
2019-12-18 00:51:57 -05:00
2016-01-08 05:53:52 -05:00
describe " # hidden_reasons " do
2022-07-27 12:14:14 -04:00
context " when verifying enum sequence " do
2016-01-08 05:53:52 -05:00
before { @hidden_reasons = Post . hidden_reasons }
it " 'flag_threshold_reached' should be at 1st position " do
expect ( @hidden_reasons [ :flag_threshold_reached ] ) . to eq ( 1 )
end
it " 'flagged_by_tl3_user' should be at 4th position " do
expect ( @hidden_reasons [ :flagged_by_tl3_user ] ) . to eq ( 4 )
end
end
end
describe " # types " do
2022-07-27 12:14:14 -04:00
context " when verifying enum sequence " do
2016-01-08 05:53:52 -05:00
before { @types = Post . types }
it " 'regular' should be at 1st position " do
expect ( @types [ :regular ] ) . to eq ( 1 )
end
it " 'whisper' should be at 4th position " do
expect ( @types [ :whisper ] ) . to eq ( 4 )
end
end
end
describe " # cook_methods " do
2022-07-27 12:14:14 -04:00
context " when verifying enum sequence " do
2016-01-08 05:53:52 -05:00
before { @cook_methods = Post . cook_methods }
it " 'regular' should be at 1st position " do
expect ( @cook_methods [ :regular ] ) . to eq ( 1 )
end
it " 'email' should be at 3rd position " do
expect ( @cook_methods [ :email ] ) . to eq ( 3 )
end
end
end
2013-05-10 16:58:23 -04:00
# Help us build a post with a raw body
def post_with_body ( body , user = nil )
args = post_args . merge ( raw : body )
args [ :user ] = user if user . present?
2019-05-08 23:28:28 -04:00
Fabricate . build ( :post , args )
2013-05-10 16:58:23 -04:00
end
2015-01-05 11:04:23 -05:00
it { is_expected . to validate_presence_of :raw }
2023-07-28 07:53:49 -04:00
it { is_expected . to validate_length_of ( :edit_reason ) . is_at_most ( 1000 ) }
2013-02-05 14:16:51 -05:00
# Min/max body lengths, respecting padding
2015-01-05 11:04:23 -05:00
it { is_expected . not_to allow_value ( " x " ) . for ( :raw ) }
it { is_expected . not_to allow_value ( " x " * ( SiteSetting . max_post_length + 1 ) ) . for ( :raw ) }
it { is_expected . not_to allow_value ( ( " " * SiteSetting . min_post_length ) + " x " ) . for ( :raw ) }
2013-02-05 14:16:51 -05:00
2015-01-05 11:04:23 -05:00
it { is_expected . to rate_limit }
2013-02-05 14:16:51 -05:00
2024-01-24 18:50:59 -05:00
fab! ( :user ) { Fabricate ( :user , refresh_auto_groups : true ) }
let ( :topic ) { Fabricate ( :topic , user : user ) }
2013-12-11 21:41:34 -05:00
let ( :post_args ) { { user : topic . user , topic : topic } }
2013-02-05 14:16:51 -05:00
2013-02-21 13:20:00 -05:00
describe " scopes " do
describe " # by_newest " do
it " returns posts ordered by created_at desc " do
2019-05-08 23:28:28 -04:00
2 . times { | t | Fabricate ( :post , created_at : t . seconds . from_now ) }
2015-01-05 11:04:23 -05:00
expect ( Post . by_newest . first . created_at ) . to be > Post . by_newest . last . created_at
2013-02-21 13:20:00 -05:00
end
end
describe " # with_user " do
it " gives you a user " do
2019-05-08 23:28:28 -04:00
Fabricate ( :post , user : Fabricate . build ( :user ) )
2015-01-05 11:04:23 -05:00
expect ( Post . with_user . first . user ) . to be_a User
2013-02-21 13:20:00 -05:00
end
end
end
2013-12-11 21:41:34 -05:00
describe " revisions and deleting/recovery " do
2022-07-27 12:14:14 -04:00
context " with a post without links " do
2019-05-08 23:28:28 -04:00
let ( :post ) { Fabricate ( :post , post_args ) }
2013-06-13 13:41:45 -04:00
before do
post . trash!
post . reload
end
2013-03-13 12:35:55 -04:00
2013-12-11 21:41:34 -05:00
it " doesn't create a new revision when deleted " do
2015-01-05 11:04:23 -05:00
expect ( post . revisions . count ) . to eq ( 0 )
2013-06-13 13:41:45 -04:00
end
describe " recovery " do
before do
post . recover!
post . reload
end
2013-12-11 21:41:34 -05:00
it " doesn't create a new revision when recovered " do
2015-01-05 11:04:23 -05:00
expect ( post . revisions . count ) . to eq ( 0 )
2013-06-13 13:41:45 -04:00
end
end
2013-03-13 12:35:55 -04:00
end
2022-07-27 12:14:14 -04:00
context " with a post with links " do
2013-06-13 13:41:45 -04:00
let ( :post ) { Fabricate ( :post_with_external_links ) }
2013-03-13 12:35:55 -04:00
before do
2013-06-13 13:41:45 -04:00
post . trash!
2013-03-13 12:35:55 -04:00
post . reload
end
2013-06-13 13:41:45 -04:00
describe " recovery " do
it " recreates the topic_link records " do
TopicLink . expects ( :extract_from ) . with ( post )
post . recover!
end
2013-03-13 12:35:55 -04:00
end
end
2020-11-11 07:49:53 -05:00
end
2013-03-13 12:35:55 -04:00
2022-07-27 12:14:14 -04:00
context " with a post with notices " do
2020-11-11 07:49:53 -05:00
let ( :post ) do
post = Fabricate ( :post , post_args )
post . upsert_custom_fields (
Post :: NOTICE = > {
type : Post . notices [ :returning_user ] ,
last_posted_at : 1 . day . ago ,
} ,
)
post
2019-03-08 03:48:35 -05:00
end
2020-11-11 07:49:53 -05:00
it " will have its notice cleared when post is trashed " do
expect { post . trash! } . to change { post . custom_fields } . to ( { } )
end
2013-03-13 12:35:55 -04:00
end
2024-04-08 23:23:11 -04:00
describe " should_secure_uploads? " do
2020-01-15 22:50:27 -05:00
let ( :topic ) { Fabricate ( :topic ) }
let! ( :post ) { Fabricate ( :post , topic : topic ) }
2023-09-05 19:39:09 -04:00
2022-09-28 19:24:33 -04:00
it " returns false if secure uploads is not enabled " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( false )
2020-01-15 22:50:27 -05:00
end
2022-09-28 19:24:33 -04:00
context " when secure uploads is enabled " do
2020-09-14 07:32:25 -04:00
before do
setup_s3
SiteSetting . authorized_extensions = " pdf|png|jpg|csv "
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2020-09-14 07:32:25 -04:00
end
2020-01-15 22:50:27 -05:00
context " if login_required " do
before { SiteSetting . login_required = true }
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2020-01-15 22:50:27 -05:00
end
2023-09-05 19:39:09 -04:00
context " if secure_uploads_pm_only " do
before { SiteSetting . secure_uploads_pm_only = true }
it " returns false " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( false )
2023-09-05 19:39:09 -04:00
end
end
2020-01-15 22:50:27 -05:00
end
context " if the topic category is read_restricted " do
let ( :category ) { Fabricate ( :private_category , group : Fabricate ( :group ) ) }
before { topic . change_category_to_id ( category . id ) }
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2020-01-15 22:50:27 -05:00
end
2023-09-05 19:39:09 -04:00
2023-11-27 22:12:28 -05:00
context " when the topic is deleted " do
before do
topic . trash!
post . reload
end
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2023-11-27 22:12:28 -05:00
end
end
2023-09-05 19:39:09 -04:00
context " if secure_uploads_pm_only " do
before { SiteSetting . secure_uploads_pm_only = true }
it " returns false " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( false )
2023-09-05 19:39:09 -04:00
end
end
2020-01-15 22:50:27 -05:00
end
context " if the post is in a PM topic " do
let ( :topic ) { Fabricate ( :private_message_topic ) }
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2020-01-15 22:50:27 -05:00
end
2023-09-05 19:39:09 -04:00
2023-11-27 22:12:28 -05:00
context " when the topic is deleted " do
before { topic . trash! }
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2023-11-27 22:12:28 -05:00
end
end
2023-09-05 19:39:09 -04:00
context " if secure_uploads_pm_only " do
before { SiteSetting . secure_uploads_pm_only = true }
it " returns true " do
2024-04-08 23:23:11 -04:00
expect ( post . should_secure_uploads? ) . to eq ( true )
2023-09-05 19:39:09 -04:00
end
end
2020-01-15 22:50:27 -05:00
end
end
end
2013-02-25 11:42:20 -05:00
describe " flagging helpers " do
2023-11-09 17:47:59 -05:00
fab! ( :post )
2021-12-15 12:41:14 -05:00
fab! ( :user ) { coding_horror }
2023-11-09 17:47:59 -05:00
fab! ( :admin )
2016-03-30 13:27:34 -04:00
2018-07-26 15:12:12 -04:00
it " is_flagged? is accurate " do
2019-01-03 12:03:01 -05:00
PostActionCreator . off_topic ( user , post )
expect ( post . reload . is_flagged? ) . to eq ( true )
2013-02-25 11:42:20 -05:00
2019-01-03 12:03:01 -05:00
PostActionDestroyer . destroy ( user , post , :off_topic )
expect ( post . reload . is_flagged? ) . to eq ( false )
2013-02-06 23:15:48 -05:00
end
2016-03-30 13:27:34 -04:00
2018-07-26 15:12:12 -04:00
it " is_flagged? is true if flag was deferred " do
2019-01-03 12:03:01 -05:00
result = PostActionCreator . off_topic ( user , post )
2023-03-02 10:40:53 -05:00
result . reviewable . perform ( admin , :ignore_and_do_nothing )
2019-01-03 12:03:01 -05:00
expect ( post . reload . is_flagged? ) . to eq ( true )
2018-07-26 15:12:12 -04:00
end
it " is_flagged? is true if flag was cleared " do
2019-01-03 12:03:01 -05:00
result = PostActionCreator . off_topic ( user , post )
result . reviewable . perform ( admin , :disagree )
expect ( post . reload . is_flagged? ) . to eq ( true )
2018-07-26 15:12:12 -04:00
end
2019-01-03 12:03:01 -05:00
it " reviewable_flag is nil when ignored " do
result = PostActionCreator . spam ( user , post )
expect ( post . reviewable_flag ) . to eq ( result . reviewable )
2016-03-30 13:27:34 -04:00
2023-03-02 10:40:53 -05:00
result . reviewable . perform ( admin , :ignore_and_do_nothing )
2019-01-03 12:03:01 -05:00
expect ( post . reviewable_flag ) . to be_nil
2016-03-30 13:27:34 -04:00
end
2018-07-26 15:12:12 -04:00
2019-01-03 12:03:01 -05:00
it " reviewable_flag is nil when disagreed " do
result = PostActionCreator . spam ( user , post )
expect ( post . reviewable_flag ) . to eq ( result . reviewable )
result . reviewable . perform ( admin , :disagree )
expect ( post . reload . reviewable_flag ) . to be_nil
2018-07-26 15:12:12 -04:00
end
2013-02-06 23:15:48 -05:00
end
2013-02-05 14:16:51 -05:00
2020-08-07 12:08:59 -04:00
describe " maximum media embeds " do
2024-01-29 04:52:02 -05:00
fab! ( :newuser ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2019-05-08 23:28:28 -04:00
let ( :post_no_images ) { Fabricate . build ( :post , post_args . merge ( user : newuser ) ) }
2013-05-10 16:58:23 -04:00
let ( :post_one_image ) { post_with_body ( " ![sherlock](http://bbc.co.uk/sherlock.jpg) " , newuser ) }
let ( :post_two_images ) do
post_with_body (
" <img src='http://discourse.org/logo.png'> <img src='http://bbc.co.uk/sherlock.jpg'> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
let ( :post_with_avatars ) do
post_with_body (
'<img alt="smiley" title=":smiley:" src="/assets/emoji/smiley.png" class="avatar"> <img alt="wink" title=":wink:" src="/assets/emoji/wink.png" class="avatar">' ,
newuser ,
2023-01-09 06:18:21 -05:00
)
end
2021-04-11 23:57:39 -04:00
let ( :post_with_favicon ) do
post_with_body ( '<img src="/images/favicons/discourse.png" class="favicon">' , newuser )
2023-01-09 06:18:21 -05:00
end
2018-02-20 20:41:27 -05:00
let ( :post_image_within_quote ) do
post_with_body ( '[quote]<img src="coolimage.png">[/quote]' , newuser )
2023-01-09 06:18:21 -05:00
end
2018-03-06 11:46:12 -05:00
let ( :post_image_within_code ) do
post_with_body ( '<code><img src="coolimage.png"></code>' , newuser )
2023-01-09 06:18:21 -05:00
end
2018-03-06 11:46:12 -05:00
let ( :post_image_within_pre ) { post_with_body ( '<pre><img src="coolimage.png"></pre>' , newuser ) }
2013-05-10 16:58:23 -04:00
let ( :post_with_thumbnail ) do
post_with_body ( '<img src="/assets/emoji/smiley.png" class="thumbnail">' , newuser )
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
let ( :post_with_two_classy_images ) do
post_with_body (
" <img src='http://discourse.org/logo.png' class='classy'> <img src='http://bbc.co.uk/sherlock.jpg' class='classy'> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2020-08-07 12:08:59 -04:00
let ( :post_with_two_embedded_media ) do
post_with_body (
'<video width="950" height="700" controls><source src="https://bbc.co.uk/news.mp4" type="video/mp4"></video><audio controls><source type="audio/mpeg" src="https://example.com/audio.mp3"></audio>' ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-02-05 14:16:51 -05:00
it " returns 0 images for an empty post " do
2020-08-07 12:08:59 -04:00
expect ( Fabricate . build ( :post ) . embedded_media_count ) . to eq ( 0 )
2013-02-05 14:16:51 -05:00
end
it " finds images from markdown " do
2020-08-07 12:08:59 -04:00
expect ( post_one_image . embedded_media_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
it " finds images from HTML " do
2020-08-07 12:08:59 -04:00
expect ( post_two_images . embedded_media_count ) . to eq ( 2 )
2013-02-05 14:16:51 -05:00
end
2013-02-12 02:43:48 -05:00
it " doesn't count avatars as images " do
2020-08-07 12:08:59 -04:00
expect ( post_with_avatars . embedded_media_count ) . to eq ( 0 )
2013-02-05 14:16:51 -05:00
end
2018-02-20 20:00:06 -05:00
it " allows images by default " do
expect ( post_one_image ) . to be_valid
end
2013-04-11 12:36:45 -04:00
it " doesn't count favicons as images " do
2017-10-15 19:46:01 -04:00
PrettyText . stubs ( :cook ) . returns ( post_with_favicon . raw )
2020-08-07 12:08:59 -04:00
expect ( post_with_favicon . embedded_media_count ) . to eq ( 0 )
2013-04-11 12:36:45 -04:00
end
it " doesn't count thumbnails as images " do
2017-10-15 19:46:01 -04:00
PrettyText . stubs ( :cook ) . returns ( post_with_thumbnail . raw )
2020-08-07 12:08:59 -04:00
expect ( post_with_thumbnail . embedded_media_count ) . to eq ( 0 )
2013-04-11 12:36:45 -04:00
end
2020-07-26 20:23:54 -04:00
it " doesn't count allowlisted images " do
Post . stubs ( :allowed_image_classes ) . returns ( [ " classy " ] )
# I dislike this, but passing in a custom allowlist is hard
2017-10-15 19:46:01 -04:00
PrettyText . stubs ( :cook ) . returns ( post_with_two_classy_images . raw )
2020-08-07 12:08:59 -04:00
expect ( post_with_two_classy_images . embedded_media_count ) . to eq ( 0 )
end
it " counts video and audio as embedded media " do
expect ( post_with_two_embedded_media . embedded_media_count ) . to eq ( 2 )
2013-02-12 02:43:48 -05:00
end
2013-02-05 14:16:51 -05:00
2024-01-24 18:50:59 -05:00
describe " embedded_media_allowed_groups " do
it " doesn't allow users outside of `embedded_media_post_allowed_groups` " do
SiteSetting . embedded_media_post_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_4 ]
post_one_image . user . change_trust_level! ( 3 )
expect ( post_one_image ) . not_to be_valid
end
it " doesn't allow users outside of `embedded_media_post_allowed_groups` in a quote " do
SiteSetting . embedded_media_post_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_4 ]
post_one_image . user . change_trust_level! ( 3 )
expect ( post_image_within_quote ) . not_to be_valid
end
it " doesn't allow users outside of `embedded_media_post_allowed_groups` in code " do
SiteSetting . embedded_media_post_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_4 ]
post_one_image . user . change_trust_level! ( 3 )
expect ( post_image_within_code ) . not_to be_valid
end
it " doesn't allow users outside of `embedded_media_post_allowed_groups` in pre " do
SiteSetting . embedded_media_post_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_4 ]
post_one_image . user . change_trust_level! ( 3 )
expect ( post_image_within_pre ) . not_to be_valid
end
it " allows users who are in a group in `embedded_media_post_allowed_groups` " do
SiteSetting . embedded_media_post_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_4 ]
post_one_image . user . change_trust_level! ( 4 )
expect ( post_one_image ) . to be_valid
end
end
2022-07-27 12:14:14 -04:00
context " with validation " do
2020-08-07 12:08:59 -04:00
before { SiteSetting . newuser_max_embedded_media = 1 }
2013-02-05 14:16:51 -05:00
2022-07-27 12:14:14 -04:00
context " with newuser " do
2013-04-17 19:11:13 -04:00
it " allows a new user to post below the limit " do
2015-01-05 11:04:23 -05:00
expect ( post_one_image ) . to be_valid
2013-03-25 12:24:46 -04:00
end
2020-08-07 12:08:59 -04:00
it " doesn't allow more than the maximum number of images " do
2015-01-05 11:04:23 -05:00
expect ( post_two_images ) . not_to be_valid
2013-03-25 12:24:46 -04:00
end
2020-08-07 12:08:59 -04:00
it " doesn't allow more than the maximum number of embedded media items " do
expect ( post_with_two_embedded_media ) . not_to be_valid
end
2013-04-17 19:11:13 -04:00
it " doesn't allow a new user to edit their post to insert an image " do
2014-09-05 01:20:39 -04:00
post_no_images . user . trust_level = TrustLevel [ 0 ]
2013-03-25 12:24:46 -04:00
post_no_images . save
2015-01-05 11:04:23 -05:00
expect {
2014-10-27 17:06:43 -04:00
post_no_images . revise ( post_no_images . user , raw : post_two_images . raw )
2013-03-25 12:24:46 -04:00
post_no_images . reload
2015-01-05 11:04:23 -05:00
} . not_to change ( post_no_images , :raw )
2013-03-25 12:24:46 -04:00
end
2013-02-05 14:16:51 -05:00
end
2013-04-17 19:11:13 -04:00
it " allows more images from a not-new account " do
2014-09-05 01:20:39 -04:00
post_two_images . user . trust_level = TrustLevel [ 1 ]
2015-01-05 11:04:23 -05:00
expect ( post_two_images ) . to be_valid
2013-02-05 14:16:51 -05:00
end
end
end
2013-07-21 20:39:17 -04:00
describe " maximum attachments " do
2024-01-29 04:52:02 -05:00
fab! ( :newuser ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2019-05-08 23:28:28 -04:00
let ( :post_no_attachments ) { Fabricate . build ( :post , post_args . merge ( user : newuser ) ) }
2019-12-18 00:51:57 -05:00
let ( :post_one_attachment ) do
post_with_body (
" <a class='attachment' href='/ #{ upload_path } /1/2082985.txt'>file.txt</a> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2019-12-18 00:51:57 -05:00
let ( :post_two_attachments ) do
post_with_body (
" <a class='attachment' href='/ #{ upload_path } /2/20947092.log'>errors.log</a> <a class='attachment' href='/ #{ upload_path } /3/283572385.3ds'>model.3ds</a> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-07-21 20:39:17 -04:00
it " returns 0 attachments for an empty post " do
2019-05-08 23:28:28 -04:00
expect ( Fabricate . build ( :post ) . attachment_count ) . to eq ( 0 )
2013-07-21 20:39:17 -04:00
end
it " finds attachments from HTML " do
2015-01-05 11:04:23 -05:00
expect ( post_two_attachments . attachment_count ) . to eq ( 2 )
2013-07-21 20:39:17 -04:00
end
2022-07-27 12:14:14 -04:00
context " with validation " do
2017-07-07 02:09:14 -04:00
before { SiteSetting . newuser_max_attachments = 1 }
2013-07-21 20:39:17 -04:00
2022-07-27 12:14:14 -04:00
context " with newuser " do
2013-07-21 20:39:17 -04:00
it " allows a new user to post below the limit " do
2015-01-05 11:04:23 -05:00
expect ( post_one_attachment ) . to be_valid
2013-07-21 20:39:17 -04:00
end
it " doesn't allow more than the maximum " do
2015-01-05 11:04:23 -05:00
expect ( post_two_attachments ) . not_to be_valid
2013-07-21 20:39:17 -04:00
end
it " doesn't allow a new user to edit their post to insert an attachment " do
2014-09-05 01:20:39 -04:00
post_no_attachments . user . trust_level = TrustLevel [ 0 ]
2013-07-21 20:39:17 -04:00
post_no_attachments . save
2015-01-05 11:04:23 -05:00
expect {
2014-10-27 17:06:43 -04:00
post_no_attachments . revise ( post_no_attachments . user , raw : post_two_attachments . raw )
2013-07-21 20:39:17 -04:00
post_no_attachments . reload
2015-01-05 11:04:23 -05:00
} . not_to change ( post_no_attachments , :raw )
2013-07-21 20:39:17 -04:00
end
end
it " allows more attachments from a not-new account " do
2014-09-05 01:20:39 -04:00
post_two_attachments . user . trust_level = TrustLevel [ 1 ]
2015-01-05 11:04:23 -05:00
expect ( post_two_attachments ) . to be_valid
2013-07-21 20:39:17 -04:00
end
end
end
2022-07-27 12:14:14 -04:00
describe " links " do
2024-01-29 04:52:02 -05:00
fab! ( :newuser ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2013-05-10 16:58:23 -04:00
let ( :no_links ) { post_with_body ( " hello world my name is evil trout " , newuser ) }
let ( :one_link ) { post_with_body ( " [jlawr](http://www.imdb.com/name/nm2225369) " , newuser ) }
let ( :two_links ) do
post_with_body (
" <a href='http://disneyland.disney.go.com/'>disney</a> <a href='http://reddit.com'>reddit</a> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
let ( :three_links ) do
post_with_body (
" http://discourse.org and http://discourse.org/another_url and http://www.imdb.com/name/nm2225369 " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
describe " raw_links " do
it " returns a blank collection for a post with no links " do
2015-01-05 11:04:23 -05:00
expect ( no_links . raw_links ) . to be_blank
2013-05-10 16:58:23 -04:00
end
it " finds a link within markdown " do
2015-01-05 11:04:23 -05:00
expect ( one_link . raw_links ) . to eq ( [ " http://www.imdb.com/name/nm2225369 " ] )
2013-05-10 16:58:23 -04:00
end
it " can find two links from html " do
2015-01-05 11:04:23 -05:00
expect ( two_links . raw_links ) . to eq ( %w[ http://disneyland.disney.go.com/ http://reddit.com ] )
2013-05-10 16:58:23 -04:00
end
it " can find three links without markup " do
2015-01-05 11:04:23 -05:00
expect ( three_links . raw_links ) . to eq (
2023-01-09 06:18:21 -05:00
%w[
2015-01-05 11:04:23 -05:00
http : / / discourse . org
http : / / discourse . org / another_url
http : / / www . imdb . com / name / nm2225369
] ,
)
2013-05-10 16:58:23 -04:00
end
end
describe " linked_hosts " do
it " returns blank with no links " do
2015-01-05 11:04:23 -05:00
expect ( no_links . linked_hosts ) . to be_blank
2013-05-10 16:58:23 -04:00
end
it " returns the host and a count for links " do
2015-01-05 11:04:23 -05:00
expect ( two_links . linked_hosts ) . to eq ( " disneyland.disney.go.com " = > 1 , " reddit.com " = > 1 )
2013-05-10 16:58:23 -04:00
end
it " it counts properly with more than one link on the same host " do
2015-01-05 11:04:23 -05:00
expect ( three_links . linked_hosts ) . to eq ( " discourse.org " = > 1 , " www.imdb.com " = > 1 )
2013-05-10 16:58:23 -04:00
end
end
describe " total host usage " do
it " has none for a regular post " do
2015-01-05 11:04:23 -05:00
expect ( no_links . total_hosts_usage ) . to be_blank
2013-05-10 16:58:23 -04:00
end
context " with a previous host " do
let ( :another_disney_link ) do
post_with_body (
" [radiator springs](http://disneyland.disney.go.com/disney-california-adventure/radiator-springs-racers/) " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
before do
another_disney_link . save
TopicLink . extract_from ( another_disney_link )
end
it " contains the new post's links, PLUS the previous one " do
2015-01-05 11:04:23 -05:00
expect ( two_links . total_hosts_usage ) . to eq (
" disneyland.disney.go.com " = > 2 ,
" reddit.com " = > 1 ,
)
2013-05-10 16:58:23 -04:00
end
end
end
end
2018-02-06 18:07:24 -05:00
describe " maximums " do
2024-01-29 04:52:02 -05:00
fab! ( :newuser ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2013-05-10 16:58:23 -04:00
let ( :post_one_link ) do
post_with_body ( " [sherlock](http://www.bbc.co.uk/programmes/b018ttws) " , newuser )
2023-01-09 06:18:21 -05:00
end
2018-02-08 18:26:56 -05:00
let ( :post_onebox ) { post_with_body ( " http://www.google.com " , newuser ) }
2018-03-06 11:46:12 -05:00
let ( :post_code_link ) { post_with_body ( " <code>http://www.google.com</code> " , newuser ) }
2013-05-10 16:58:23 -04:00
let ( :post_two_links ) do
post_with_body (
" <a href='http://discourse.org'>discourse</a> <a href='http://twitter.com'>twitter</a> " ,
newuser ,
)
2023-01-09 06:18:21 -05:00
end
2013-05-10 16:58:23 -04:00
let ( :post_with_mentions ) do
post_with_body ( " hello @ #{ newuser . username } how are you doing? " , newuser )
2023-01-09 06:18:21 -05:00
end
2013-02-05 14:16:51 -05:00
2013-03-25 13:12:15 -04:00
it " returns 0 links for an empty post " do
2019-05-08 23:28:28 -04:00
expect ( Fabricate . build ( :post ) . link_count ) . to eq ( 0 )
2013-02-05 14:16:51 -05:00
end
2013-03-25 13:12:15 -04:00
it " returns 0 links for a post with mentions " do
2015-01-05 11:04:23 -05:00
expect ( post_with_mentions . link_count ) . to eq ( 0 )
2013-03-25 13:12:15 -04:00
end
it " finds links from markdown " do
2015-01-05 11:04:23 -05:00
expect ( post_one_link . link_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
2013-03-25 13:12:15 -04:00
it " finds links from HTML " do
2015-01-05 11:04:23 -05:00
expect ( post_two_links . link_count ) . to eq ( 2 )
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with validation " do
2017-07-07 02:09:14 -04:00
before { SiteSetting . newuser_max_links = 1 }
2013-02-05 14:16:51 -05:00
2022-07-27 12:14:14 -04:00
context " with newuser " do
2013-03-25 12:24:46 -04:00
it " returns true when within the amount of links allowed " do
2015-01-05 11:04:23 -05:00
expect ( post_one_link ) . to be_valid
2013-03-25 12:24:46 -04:00
end
it " doesn't allow more links than allowed " do
2015-01-05 11:04:23 -05:00
expect ( post_two_links ) . not_to be_valid
2013-03-25 12:24:46 -04:00
end
2013-02-05 14:16:51 -05:00
end
2018-02-06 18:07:24 -05:00
it " allows multiple links for basic accounts " do
2014-09-05 01:20:39 -04:00
post_two_links . user . trust_level = TrustLevel [ 1 ]
2015-01-05 11:04:23 -05:00
expect ( post_two_links ) . to be_valid
2013-02-05 14:16:51 -05:00
end
2013-03-25 12:24:46 -04:00
2024-01-18 01:08:40 -05:00
context " when posting links is limited to certain TL groups " do
2018-02-08 18:26:56 -05:00
it " considers oneboxes links " do
2024-01-18 01:08:40 -05:00
SiteSetting . post_links_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_3 ]
post_onebox . user . change_trust_level! ( TrustLevel [ 2 ] )
2018-02-08 18:26:56 -05:00
expect ( post_onebox ) . not_to be_valid
end
2018-03-06 11:46:12 -05:00
it " considers links within code " do
2024-01-18 01:08:40 -05:00
SiteSetting . post_links_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_3 ]
post_onebox . user . change_trust_level! ( TrustLevel [ 2 ] )
2018-03-06 11:46:12 -05:00
expect ( post_code_link ) . not_to be_valid
end
2024-01-18 01:08:40 -05:00
it " doesn't allow allow links if user is not in allowed groups " do
SiteSetting . post_links_allowed_groups = Group :: AUTO_GROUPS [ :trust_level_2 ]
post_two_links . user . change_trust_level! ( TrustLevel [ 1 ] )
2018-02-08 18:26:56 -05:00
expect ( post_one_link ) . not_to be_valid
end
2018-06-13 14:57:32 -04:00
2020-07-26 20:23:54 -04:00
it " will skip the check for allowlisted domains " do
SiteSetting . allowed_link_domains = " www.bbc.co.uk "
2024-01-18 01:08:40 -05:00
SiteSetting . post_links_allowed_groups = " 12 "
post_two_links . user . change_trust_level! ( TrustLevel [ 1 ] )
2018-06-13 14:57:32 -04:00
expect ( post_one_link ) . to be_valid
end
2018-02-06 18:07:24 -05:00
end
2013-02-05 14:16:51 -05:00
end
end
2013-03-25 12:24:46 -04:00
describe " @mentions " do
2022-07-27 12:14:14 -04:00
context " with raw_mentions " do
2013-02-05 14:16:51 -05:00
it " returns an empty array with no matches " do
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " Hello Jake and Finn! " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( [ ] )
2013-02-05 14:16:51 -05:00
end
it " returns lowercase unique versions of the mentions " do
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " @Jake @Finn @Jake " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( %w[ jake finn ] )
2013-02-05 14:16:51 -05:00
end
it " ignores pre " do
2017-07-14 08:27:28 -04:00
# we need to force an inline
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " p <pre>@Jake</pre> @Finn " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( [ " finn " ] )
2013-02-05 14:16:51 -05:00
end
it " catches content between pre tags " do
2017-07-14 08:27:28 -04:00
# per common mark we need to force an inline
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " a <pre>hello</pre> @Finn <pre></pre> " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( [ " finn " ] )
2013-02-05 14:16:51 -05:00
end
it " ignores code " do
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " @Jake `@Finn` " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( [ " jake " ] )
2013-02-25 11:42:20 -05:00
end
2013-02-05 14:16:51 -05:00
it " ignores quotes " do
2019-05-08 23:28:28 -04:00
post =
Fabricate . build (
:post ,
post_args . merge ( raw : " [quote= \" Evil Trout \" ] \n @Jake \n [/quote] \n @Finn " ) ,
)
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( [ " finn " ] )
2013-02-25 11:42:20 -05:00
end
2013-02-05 14:16:51 -05:00
2013-03-23 20:57:00 -04:00
it " handles underscore in username " do
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " @Jake @Finn @Jake_Old " ) )
2015-01-05 11:04:23 -05:00
expect ( post . raw_mentions ) . to eq ( %w[ jake finn jake_old ] )
2013-03-23 20:57:00 -04:00
end
2016-02-23 14:57:54 -05:00
it " handles hyphen in groupname " do
2019-05-08 23:28:28 -04:00
post = Fabricate . build ( :post , post_args . merge ( raw : " @org-board " ) )
2016-02-23 14:57:54 -05:00
expect ( post . raw_mentions ) . to eq ( [ " org-board " ] )
end
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with max mentions " do
2024-01-29 04:52:02 -05:00
fab! ( :newuser ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2013-05-10 16:58:23 -04:00
let ( :post_with_one_mention ) { post_with_body ( " @Jake is the person I'm mentioning " , newuser ) }
let ( :post_with_two_mentions ) do
post_with_body ( " @Jake @Finn are the people I'm mentioning " , newuser )
2023-01-09 06:18:21 -05:00
end
2013-03-25 12:24:46 -04:00
2022-07-27 12:14:14 -04:00
context " with new user " do
2013-03-25 12:24:46 -04:00
before do
2017-07-07 02:09:14 -04:00
SiteSetting . newuser_max_mentions_per_post = 1
SiteSetting . max_mentions_per_post = 5
2013-03-25 12:24:46 -04:00
end
2013-04-17 19:11:13 -04:00
it " allows a new user to have newuser_max_mentions_per_post mentions " do
2015-01-05 11:04:23 -05:00
expect ( post_with_one_mention ) . to be_valid
2013-03-25 12:24:46 -04:00
end
2013-04-17 19:11:13 -04:00
it " doesn't allow a new user to have more than newuser_max_mentions_per_post mentions " do
2015-01-05 11:04:23 -05:00
expect ( post_with_two_mentions ) . not_to be_valid
2013-03-25 12:24:46 -04:00
end
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " when not a new user " do
2013-03-25 12:24:46 -04:00
before do
2017-07-07 02:09:14 -04:00
SiteSetting . newuser_max_mentions_per_post = 0
SiteSetting . max_mentions_per_post = 1
2013-03-25 12:24:46 -04:00
end
2024-02-29 06:24:37 -05:00
it " allows max_mentions_per_post mentions " do
2014-09-05 01:20:39 -04:00
post_with_one_mention . user . trust_level = TrustLevel [ 1 ]
2015-01-05 11:04:23 -05:00
expect ( post_with_one_mention ) . to be_valid
2013-03-25 12:24:46 -04:00
end
it " doesn't allow to have more than max_mentions_per_post mentions " do
2014-09-05 01:20:39 -04:00
post_with_two_mentions . user . trust_level = TrustLevel [ 1 ]
2015-01-05 11:04:23 -05:00
expect ( post_with_two_mentions ) . not_to be_valid
2013-03-25 12:24:46 -04:00
end
2013-02-05 14:16:51 -05:00
end
end
end
2022-07-27 12:14:14 -04:00
describe " validation " do
2013-06-13 04:18:17 -04:00
it " validates our default post " do
2019-05-08 23:28:28 -04:00
expect ( Fabricate . build ( :post , post_args ) ) . to be_valid
2013-06-13 04:18:17 -04:00
end
2017-01-16 00:24:47 -05:00
it " create blank posts as invalid " do
2019-05-08 23:28:28 -04:00
expect ( Fabricate . build ( :post , raw : " " ) ) . not_to be_valid
2013-06-13 04:18:17 -04:00
end
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
describe " raw_hash " do
2013-02-05 14:16:51 -05:00
let ( :raw ) { " this is our test post body " }
2013-05-10 16:58:23 -04:00
let ( :post ) { post_with_body ( raw ) }
2013-02-25 11:42:20 -05:00
2013-02-05 14:16:51 -05:00
it " returns a value " do
2015-01-05 11:04:23 -05:00
expect ( post . raw_hash ) . to be_present
2013-02-05 14:16:51 -05:00
end
it " returns blank for a nil body " do
post . raw = nil
2015-01-05 11:04:23 -05:00
expect ( post . raw_hash ) . to be_blank
2013-02-05 14:16:51 -05:00
end
it " returns the same value for the same raw " do
2015-01-05 11:04:23 -05:00
expect ( post . raw_hash ) . to eq ( post_with_body ( raw ) . raw_hash )
2013-02-05 14:16:51 -05:00
end
it " returns a different value for a different raw " do
2015-01-05 11:04:23 -05:00
expect ( post . raw_hash ) . not_to eq ( post_with_body ( " something else " ) . raw_hash )
2013-02-05 14:16:51 -05:00
end
2013-06-17 15:57:13 -04:00
it " returns a different value with different text case " do
2015-01-05 11:04:23 -05:00
expect ( post . raw_hash ) . not_to eq ( post_with_body ( " THIS is OUR TEST post BODy " ) . raw_hash )
2013-02-05 14:16:51 -05:00
end
end
2022-07-27 12:14:14 -04:00
describe " revise " do
2019-05-08 23:28:28 -04:00
let ( :post ) { Fabricate ( :post , post_args ) }
2013-02-05 14:16:51 -05:00
let ( :first_version_at ) { post . last_version_at }
2013-12-11 21:41:34 -05:00
it " has no revision " do
2015-01-05 11:04:23 -05:00
expect ( post . revisions . size ) . to eq ( 0 )
expect ( first_version_at ) . to be_present
expect ( post . revise ( post . user , raw : post . raw ) ) . to eq ( false )
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with the same body " do
2013-12-11 21:41:34 -05:00
it " doesn't change version " do
2015-01-05 11:04:23 -05:00
expect {
post . revise ( post . user , raw : post . raw )
post . reload
} . not_to change ( post , :version )
2013-02-05 14:16:51 -05:00
end
end
2022-07-27 12:14:14 -04:00
context " with grace period editing & edit windows " do
2017-07-07 02:09:14 -04:00
before { SiteSetting . editing_grace_period = 1 . minute . to_i }
2013-04-30 08:54:30 -04:00
2014-10-27 17:06:43 -04:00
it " works " do
revised_at = post . updated_at + 2 . minutes
new_revised_at = revised_at + 2 . minutes
2013-02-05 14:16:51 -05:00
2021-06-30 21:27:11 -04:00
# grace period edit
2014-10-27 17:06:43 -04:00
post . revise ( post . user , { raw : " updated body " } , revised_at : post . updated_at + 10 . seconds )
2013-02-05 14:16:51 -05:00
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . version ) . to eq ( 1 )
expect ( post . public_version ) . to eq ( 1 )
expect ( post . revisions . size ) . to eq ( 0 )
expect ( post . last_version_at . to_i ) . to eq ( first_version_at . to_i )
2013-02-05 14:16:51 -05:00
2014-10-27 17:06:43 -04:00
# revision much later
post . revise ( post . user , { raw : " another updated body " } , revised_at : revised_at )
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . version ) . to eq ( 2 )
expect ( post . public_version ) . to eq ( 2 )
expect ( post . revisions . size ) . to eq ( 1 )
expect ( post . last_version_at . to_i ) . to eq ( revised_at . to_i )
2013-02-05 14:16:51 -05:00
2014-10-27 17:06:43 -04:00
# new edit window
post . revise (
post . user ,
{ raw : " yet another updated body " } ,
revised_at : revised_at + 10 . seconds ,
)
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . version ) . to eq ( 2 )
expect ( post . public_version ) . to eq ( 2 )
expect ( post . revisions . size ) . to eq ( 1 )
expect ( post . last_version_at . to_i ) . to eq ( revised_at . to_i )
2013-02-05 14:16:51 -05:00
2014-10-27 17:06:43 -04:00
# after second window
post . revise (
post . user ,
{ raw : " yet another, another updated body " } ,
revised_at : new_revised_at ,
)
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . version ) . to eq ( 3 )
expect ( post . public_version ) . to eq ( 3 )
expect ( post . revisions . size ) . to eq ( 2 )
expect ( post . last_version_at . to_i ) . to eq ( new_revised_at . to_i )
2013-02-05 14:16:51 -05:00
end
end
2022-07-27 12:14:14 -04:00
context " with rate limiter " do
2021-12-15 12:41:14 -05:00
let ( :changed_by ) { coding_horror }
2013-02-25 11:42:20 -05:00
2013-02-05 14:16:51 -05:00
it " triggers a rate limiter " do
2013-02-09 10:33:07 -05:00
EditRateLimiter . any_instance . expects ( :performed! )
2014-10-27 17:06:43 -04:00
post . revise ( changed_by , raw : " updated body " )
2013-02-05 14:16:51 -05:00
end
end
2022-07-27 12:14:14 -04:00
context " with a new body " do
2021-12-15 12:41:14 -05:00
let ( :changed_by ) { coding_horror }
2014-10-27 17:06:43 -04:00
let! ( :result ) { post . revise ( changed_by , raw : " updated body " ) }
2013-02-05 14:16:51 -05:00
2013-04-22 03:45:03 -04:00
it " acts correctly " do
2015-01-05 11:04:23 -05:00
expect ( result ) . to eq ( true )
expect ( post . raw ) . to eq ( " updated body " )
expect ( post . invalidate_oneboxes ) . to eq ( true )
expect ( post . version ) . to eq ( 2 )
expect ( post . public_version ) . to eq ( 2 )
expect ( post . revisions . size ) . to eq ( 1 )
expect ( post . revisions . first . user ) . to be_present
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " when second poster posts again quickly " do
2021-06-30 21:27:11 -04:00
it " is a grace period edit, because the second poster posted again quickly " do
2018-03-07 00:44:21 -05:00
SiteSetting . editing_grace_period = 1 . minute . to_i
2014-10-27 17:06:43 -04:00
post . revise (
changed_by ,
{ raw : " yet another updated body " } ,
revised_at : post . updated_at + 10 . seconds ,
)
2013-02-05 14:16:51 -05:00
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . version ) . to eq ( 2 )
expect ( post . public_version ) . to eq ( 2 )
expect ( post . revisions . size ) . to eq ( 1 )
2013-02-25 11:42:20 -05:00
end
2013-02-05 14:16:51 -05:00
end
end
end
2016-10-24 00:02:38 -04:00
describe " before save " do
2019-12-18 00:51:57 -05:00
let ( :cooked ) do
" <p><div class= \" lightbox-wrapper \" ><a data-download-href= \" //localhost:3000/ #{ upload_path } /34784374092783e2fef84b8bc96d9b54c11ceea0 \" href= \" //localhost:3000/ #{ upload_path } /original/1X/34784374092783e2fef84b8bc96d9b54c11ceea0.gif \" class= \" lightbox \" title= \" Sword reworks.gif \" ><img src= \" //localhost:3000/ #{ upload_path } /optimized/1X/34784374092783e2fef84b8bc96d9b54c11ceea0_1_690x276.gif \" width= \" 690 \" height= \" 276 \" ><div class= \" meta \" > \n <span class= \" filename \" >Sword reworks.gif</span><span class= \" informations \" >1000x400 1000 KB</span><span class= \" expand \" ></span> \n </div></a></div></p> "
2023-01-09 06:18:21 -05:00
end
2016-10-24 00:02:38 -04:00
let ( :post ) do
2019-05-08 23:28:28 -04:00
Fabricate (
:post ,
2019-12-18 00:51:57 -05:00
raw :
" <img src= \" / #{ upload_path } /original/1X/34784374092783e2fef84b8bc96d9b54c11ceea0.gif \" width= \" 690 \" height= \" 276 \" > " ,
2016-10-24 00:02:38 -04:00
cooked : cooked ,
)
end
it " should not cook the post if raw has not been changed " do
post . save!
expect ( post . cooked ) . to eq ( cooked )
end
end
2013-02-05 14:16:51 -05:00
describe " after save " do
2019-05-08 23:28:28 -04:00
let ( :post ) { Fabricate ( :post , post_args ) }
2013-02-05 14:16:51 -05:00
2013-04-22 03:45:03 -04:00
it " has correct info set " do
2015-01-05 11:04:23 -05:00
expect ( post . user_deleted? ) . to eq ( false )
expect ( post . post_number ) . to be_present
expect ( post . excerpt ) . to be_present
expect ( post . post_type ) . to eq ( Post . types [ :regular ] )
expect ( post . revisions ) . to be_blank
expect ( post . cooked ) . to be_present
expect ( post . external_id ) . to be_present
expect ( post . quote_count ) . to eq ( 0 )
expect ( post . replies ) . to be_blank
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with extract_quoted_post_numbers " do
2019-05-08 23:28:28 -04:00
let! ( :post ) { Fabricate ( :post , post_args ) }
let ( :reply ) { Fabricate . build ( :post , post_args ) }
2013-02-05 14:16:51 -05:00
it " finds the quote when in the same topic " do
reply . raw =
" [quote= \" EvilTrout, post: #{ post . post_number } , topic: #{ post . topic_id } \" ]hello[/quote] "
reply . extract_quoted_post_numbers
2015-01-05 11:04:23 -05:00
expect ( reply . quoted_post_numbers ) . to eq ( [ post . post_number ] )
2013-02-05 14:16:51 -05:00
end
it " doesn't find the quote in a different topic " do
reply . raw =
" [quote= \" EvilTrout, post: #{ post . post_number } , topic: #{ post . topic_id + 1 } \" ]hello[/quote] "
reply . extract_quoted_post_numbers
2015-01-05 11:04:23 -05:00
expect ( reply . quoted_post_numbers ) . to be_blank
2013-02-05 14:16:51 -05:00
end
2018-07-10 04:17:28 -04:00
it " doesn't find the quote in the same post " do
2019-05-08 23:28:28 -04:00
reply = Fabricate . build ( :post , post_args . merge ( post_number : 646 ) )
2018-07-10 04:17:28 -04:00
reply . raw =
" [quote= \" EvilTrout, post: #{ reply . post_number } , topic: #{ post . topic_id } \" ]hello[/quote] "
reply . extract_quoted_post_numbers
expect ( reply . quoted_post_numbers ) . to be_blank
end
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with a new reply " do
2023-11-09 17:47:59 -05:00
fab! ( :topic )
2021-12-15 12:41:14 -05:00
let ( :other_user ) { coding_horror }
2013-03-18 15:54:08 -04:00
let ( :reply_text ) { " [quote= \" Evil Trout, post:1 \" ] \n hello \n [/quote] \n Hmmm! " }
2019-05-08 23:28:28 -04:00
let! ( :post ) do
PostCreator . new ( topic . user , raw : Fabricate . build ( :post ) . raw , topic_id : topic . id ) . create
2023-01-09 06:18:21 -05:00
end
2013-03-18 15:54:08 -04:00
let! ( :reply ) do
PostCreator . new (
other_user ,
raw : reply_text ,
topic_id : topic . id ,
reply_to_post_number : post . post_number ,
) . create
2023-01-09 06:18:21 -05:00
end
2013-02-05 14:16:51 -05:00
it " has a quote " do
2015-01-05 11:04:23 -05:00
expect ( reply . quote_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
it " has a reply to the user of the original user " do
2015-01-05 11:04:23 -05:00
expect ( reply . reply_to_user ) . to eq ( post . user )
2013-02-05 14:16:51 -05:00
end
it " increases the reply count of the parent " do
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . reply_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
it " increases the reply count of the topic " do
topic . reload
2015-01-05 11:04:23 -05:00
expect ( topic . reply_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
it " is the child of the parent post " do
2015-01-05 11:04:23 -05:00
expect ( post . replies ) . to eq ( [ reply ] )
2013-02-05 14:16:51 -05:00
end
it " doesn't change the post count when you edit the reply " do
reply . raw = " updated raw "
reply . save
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . reply_count ) . to eq ( 1 )
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
context " with a multi-quote reply " do
2013-03-18 15:54:08 -04:00
let! ( :multi_reply ) do
raw =
" [quote= \" Evil Trout, post:1 \" ]post1 quote[/quote] \n Aha! \n [quote= \" Evil Trout, post:2 \" ]post2 quote[/quote] \n Neat-o "
PostCreator . new (
other_user ,
raw : raw ,
topic_id : topic . id ,
reply_to_post_number : post . post_number ,
) . create
end
2013-02-05 14:16:51 -05:00
2013-04-22 03:45:03 -04:00
it " has the correct info set " do
2015-01-05 11:04:23 -05:00
expect ( multi_reply . quote_count ) . to eq ( 2 )
expect ( post . replies . include? ( multi_reply ) ) . to eq ( true )
expect ( reply . replies . include? ( multi_reply ) ) . to eq ( true )
2013-02-05 14:16:51 -05:00
end
end
end
end
2022-07-27 12:14:14 -04:00
describe " summary " do
2019-05-08 23:28:28 -04:00
let! ( :p1 ) { Fabricate ( :post , post_args . merge ( score : 4 , percent_rank : 0 . 33 ) ) }
let! ( :p2 ) { Fabricate ( :post , post_args . merge ( score : 10 , percent_rank : 0 . 66 ) ) }
let! ( :p3 ) { Fabricate ( :post , post_args . merge ( score : 5 , percent_rank : 0 . 99 ) ) }
fab! ( :p4 ) { Fabricate ( :post , percent_rank : 0 . 99 ) }
2013-02-05 14:16:51 -05:00
2013-11-18 12:48:26 -05:00
it " returns the OP and posts above the threshold in summary mode " do
2017-07-07 02:09:14 -04:00
SiteSetting . summary_percent_filter = 66
2018-06-21 00:00:54 -04:00
expect ( Post . summary ( topic . id ) . order ( :post_number ) ) . to eq ( [ p1 , p2 ] )
expect ( Post . summary ( p4 . topic . id ) ) . to eq ( [ p4 ] )
2013-02-05 14:16:51 -05:00
end
end
2022-07-27 12:14:14 -04:00
describe " sort_order " do
context " with a regular topic " do
2019-05-08 23:28:28 -04:00
let! ( :p1 ) { Fabricate ( :post , post_args ) }
let! ( :p2 ) { Fabricate ( :post , post_args ) }
let! ( :p3 ) { Fabricate ( :post , post_args ) }
2013-02-05 14:16:51 -05:00
it " defaults to created order " do
2015-01-05 11:04:23 -05:00
expect ( Post . regular_order ) . to eq ( [ p1 , p2 , p3 ] )
2013-02-05 14:16:51 -05:00
end
end
2013-08-06 17:42:36 -04:00
end
2022-07-27 12:14:14 -04:00
describe " reply_history " do
2019-05-08 23:28:28 -04:00
let! ( :p1 ) { Fabricate ( :post , post_args ) }
let! ( :p2 ) { Fabricate ( :post , post_args . merge ( reply_to_post_number : p1 . post_number ) ) }
let! ( :p3 ) { Fabricate ( :post , post_args ) }
let! ( :p4 ) { Fabricate ( :post , post_args . merge ( reply_to_post_number : p2 . post_number ) ) }
2013-08-06 17:42:36 -04:00
it " returns the posts in reply to this post " do
2015-01-05 11:04:23 -05:00
expect ( p4 . reply_history ) . to eq ( [ p1 , p2 ] )
expect ( p4 . reply_history ( 1 ) ) . to eq ( [ p2 ] )
expect ( p3 . reply_history ) . to be_blank
expect ( p2 . reply_history ) . to eq ( [ p1 ] )
2013-08-06 17:42:36 -04:00
end
2013-02-05 14:16:51 -05:00
end
2022-07-27 12:14:14 -04:00
describe " reply_ids " do
2023-11-09 17:47:59 -05:00
fab! ( :topic )
2019-05-08 23:28:28 -04:00
let! ( :p1 ) { Fabricate ( :post , topic : topic , post_number : 1 ) }
let! ( :p2 ) { Fabricate ( :post , topic : topic , post_number : 2 , reply_to_post_number : 1 ) }
let! ( :p3 ) { Fabricate ( :post , topic : topic , post_number : 3 ) }
let! ( :p4 ) { Fabricate ( :post , topic : topic , post_number : 4 , reply_to_post_number : 2 ) }
let! ( :p5 ) { Fabricate ( :post , topic : topic , post_number : 5 , reply_to_post_number : 4 ) }
let! ( :p6 ) { Fabricate ( :post , topic : topic , post_number : 6 ) }
2017-12-13 16:12:06 -05:00
before do
PostReply . create! ( post : p1 , reply : p2 )
PostReply . create! ( post : p2 , reply : p4 )
2017-12-13 18:43:48 -05:00
PostReply . create! ( post : p2 , reply : p6 ) # simulates p6 quoting p2
PostReply . create! ( post : p3 , reply : p5 ) # simulates p5 quoting p3
2017-12-13 16:12:06 -05:00
PostReply . create! ( post : p4 , reply : p5 )
2017-12-14 18:38:14 -05:00
PostReply . create! ( post : p6 , reply : p6 ) # https://meta.discourse.org/t/topic-quoting-itself-displays-reply-indicator/76085
2023-01-09 06:18:21 -05:00
end
2017-12-13 16:12:06 -05:00
it " returns the reply ids and their level " do
2017-12-13 18:43:48 -05:00
expect ( p1 . reply_ids ) . to eq (
[ { id : p2 . id , level : 1 } , { id : p4 . id , level : 2 } , { id : p6 . id , level : 2 } ] ,
)
expect ( p2 . reply_ids ) . to eq ( [ { id : p4 . id , level : 1 } , { id : p6 . id , level : 1 } ] )
expect ( p3 . reply_ids ) . to be_empty # has no replies
expect ( p4 . reply_ids ) . to be_empty # p5 replies to 2 posts (p4 and p3)
expect ( p5 . reply_ids ) . to be_empty # has no replies
2017-12-14 18:38:14 -05:00
expect ( p6 . reply_ids ) . to be_empty # quotes itself
2017-12-13 16:12:06 -05:00
end
2020-02-03 13:12:27 -05:00
it " ignores posts moved to other topics " do
p2 . update_column ( :topic_id , Fabricate ( :topic ) . id )
expect ( p1 . reply_ids ) . to be_blank
end
2020-02-03 13:34:35 -05:00
it " doesn't include the same reply twice " do
PostReply . create! ( post : p4 , reply : p1 )
expect ( p1 . reply_ids . size ) . to eq ( 4 )
end
2018-04-20 17:05:51 -04:00
it " does not skip any replies " do
expect ( p1 . reply_ids ( only_replies_to_single_post : false ) ) . to eq (
2023-01-09 06:18:21 -05:00
[
2018-04-20 17:05:51 -04:00
{ id : p2 . id , level : 1 } ,
{ id : p4 . id , level : 2 } ,
{ id : p5 . id , level : 3 } ,
{ id : p6 . id , level : 2 } ,
2023-01-09 06:18:21 -05:00
] ,
2018-04-20 17:05:51 -04:00
)
expect ( p2 . reply_ids ( only_replies_to_single_post : false ) ) . to eq (
[ { id : p4 . id , level : 1 } , { id : p5 . id , level : 2 } , { id : p6 . id , level : 1 } ] ,
2023-01-09 06:18:21 -05:00
)
2018-04-20 17:05:51 -04:00
expect ( p3 . reply_ids ( only_replies_to_single_post : false ) ) . to eq ( [ { id : p5 . id , level : 1 } ] )
expect ( p4 . reply_ids ( only_replies_to_single_post : false ) ) . to eq ( [ { id : p5 . id , level : 1 } ] )
expect ( p5 . reply_ids ( only_replies_to_single_post : false ) ) . to be_empty # has no replies
expect ( p6 . reply_ids ( only_replies_to_single_post : false ) ) . to be_empty # quotes itself
end
2017-12-13 16:12:06 -05:00
end
2013-04-22 03:45:03 -04:00
describe " urls " do
2013-05-10 16:58:23 -04:00
it " no-ops for empty list " do
2015-01-05 11:04:23 -05:00
expect ( Post . urls ( [ ] ) ) . to eq ( { } )
2013-04-22 03:45:03 -04:00
end
2013-05-10 16:58:23 -04:00
# integration test -> should move to centralized integration test
it " finds urls for posts presented " do
2019-05-08 23:28:28 -04:00
p1 = Fabricate ( :post )
p2 = Fabricate ( :post )
2015-01-05 11:04:23 -05:00
expect ( Post . urls ( [ p1 . id , p2 . id ] ) ) . to eq ( p1 . id = > p1 . url , p2 . id = > p2 . url )
2013-04-22 03:45:03 -04:00
end
end
2013-10-15 10:21:30 -04:00
describe " details " do
it " adds details " do
post = Fabricate . build ( :post )
post . add_detail ( " key " , " value " )
2015-01-05 11:04:23 -05:00
expect ( post . post_details . size ) . to eq ( 1 )
expect ( post . post_details . first . key ) . to eq ( " key " )
expect ( post . post_details . first . value ) . to eq ( " value " )
2013-10-15 10:21:30 -04:00
end
it " can find a post by a detail " do
detail = Fabricate ( :post_detail )
post = detail . post
2015-01-05 11:04:23 -05:00
expect ( Post . find_by_detail ( detail . key , detail . value ) . id ) . to eq ( post . id )
2013-10-15 10:21:30 -04:00
end
end
2014-01-15 11:34:17 -05:00
describe " cooking " do
let ( :post ) do
2024-01-18 01:08:40 -05:00
Fabricate . build (
:post ,
post_args . merge (
raw : " please read my blog http://blog.example.com " ,
user : Fabricate ( :user , refresh_auto_groups : true ) ,
) ,
)
2023-01-09 06:18:21 -05:00
end
2014-01-15 11:34:17 -05:00
2018-09-16 22:02:20 -04:00
it " should unconditionally follow links for staff " do
SiteSetting . tl3_links_no_follow = true
post . user . trust_level = 1
post . user . moderator = true
post . save
expect ( post . cooked ) . not_to match ( / nofollow / )
end
2014-01-15 11:34:17 -05:00
it " should add nofollow to links in the post for trust levels below 3 " do
post . user . trust_level = 2
post . save
2020-09-10 11:59:51 -04:00
expect ( post . cooked ) . to match ( / noopener nofollow ugc / )
2014-01-15 11:34:17 -05:00
end
2014-09-04 16:16:46 -04:00
it " when tl3_links_no_follow is false, should not add nofollow for trust level 3 and higher " do
2017-07-07 02:09:14 -04:00
SiteSetting . tl3_links_no_follow = false
2014-01-15 11:34:17 -05:00
post . user . trust_level = 3
post . save
2015-01-05 11:04:23 -05:00
expect ( post . cooked ) . not_to match ( / nofollow / )
2014-01-15 11:34:17 -05:00
end
2014-07-14 13:34:21 -04:00
2014-09-04 16:16:46 -04:00
it " when tl3_links_no_follow is true, should add nofollow for trust level 3 and higher " do
2017-07-07 02:09:14 -04:00
SiteSetting . tl3_links_no_follow = true
2014-07-14 13:34:21 -04:00
post . user . trust_level = 3
post . save
2020-09-10 11:59:51 -04:00
expect ( post . cooked ) . to match ( / noopener nofollow ugc / )
2014-07-14 13:34:21 -04:00
end
2018-11-22 03:01:03 -05:00
FEATURE: Generic hashtag autocomplete lookup and markdown cooking (#18937)
This commit fleshes out and adds functionality for the new `#hashtag` search and
lookup system, still hidden behind the `enable_experimental_hashtag_autocomplete`
feature flag.
**Serverside**
We have two plugin API registration methods that are used to define data sources
(`register_hashtag_data_source`) and hashtag result type priorities depending on
the context (`register_hashtag_type_in_context`). Reading the comments in plugin.rb
should make it clear what these are doing. Reading the `HashtagAutocompleteService`
in full will likely help a lot as well.
Each data source is responsible for providing its own **lookup** and **search**
method that returns hashtag results based on the arguments provided. For example,
the category hashtag data source has to take into account parent categories and
how they relate, and each data source has to define their own icon to use for the
hashtag, and so on.
The `Site` serializer has two new attributes that source data from `HashtagAutocompleteService`.
There is `hashtag_icons` that is just a simple array of all the different icons that
can be used for allowlisting in our markdown pipeline, and there is `hashtag_context_configurations`
that is used to store the type priority orders for each registered context.
When sending emails, we cannot render the SVG icons for hashtags, so
we need to change the HTML hashtags to the normal `#hashtag` text.
**Markdown**
The `hashtag-autocomplete.js` file is where I have added the new `hashtag-autocomplete`
markdown rule, and like all of our rules this is used to cook the raw text on both the clientside
and on the serverside using MiniRacer. Only on the server side do we actually reach out to
the database with the `hashtagLookup` function, on the clientside we just render a plainer
version of the hashtag HTML. Only in the composer preview do we do further lookups based
on this.
This rule is the first one (that I can find) that uses the `currentUser` based on a passed
in `user_id` for guardian checks in markdown rendering code. This is the `last_editor_id`
for both the post and chat message. In some cases we need to cook without a user present,
so the `Discourse.system_user` is used in this case.
**Chat Channels**
This also contains the changes required for chat so that chat channels can be used
as a data source for hashtag searches and lookups. This data source will only be
used when `enable_experimental_hashtag_autocomplete` is `true`, so we don't have
to worry about channel results suddenly turning up.
------
**Known Rough Edges**
- Onebox excerpts will not render the icon svg/use tags, I plan to address that in a follow up PR
- Selecting a hashtag + pressing the Quote button will result in weird behaviour, I plan to address that in a follow up PR
- Mixed hashtag contexts for hashtags without a type suffix will not work correctly, e.g. #ux which is both a category and a channel slug will resolve to a category when used inside a post or within a [chat] transcript in that post. Users can get around this manually by adding the correct suffix, for example ::channel. We may get to this at some point in future
- Icons will not show for the hashtags in emails since SVG support is so terrible in email (this is not likely to be resolved, but still noting for posterity)
- Additional refinements and review fixes wil
2022-11-20 17:37:06 -05:00
it " passes the last_editor_id as the markdown user_id option " do
post . save
post . reload
PostAnalyzer
. any_instance
. expects ( :cook )
. with ( post . raw , { cook_method : Post . cook_methods [ :regular ] , user_id : post . last_editor_id } )
post . cook ( post . raw )
user_editor = Fabricate ( :user )
post . update! ( last_editor_id : user_editor . id )
PostAnalyzer
. any_instance
. expects ( :cook )
. with ( post . raw , { cook_method : Post . cook_methods [ :regular ] , user_id : user_editor . id } )
post . cook ( post . raw )
end
2018-11-22 03:01:03 -05:00
describe " mentions " do
2019-05-06 23:12:20 -04:00
fab! ( :group ) do
2018-11-22 03:01:03 -05:00
Fabricate (
:group ,
2019-12-12 06:13:40 -05:00
visibility_level : Group . visibility_levels [ :members ] ,
2018-11-22 03:01:03 -05:00
mentionable_level : Group :: ALIAS_LEVELS [ :members_mods_and_admins ] ,
)
end
2019-03-14 10:47:38 -04:00
before { Jobs . run_immediately! }
2018-11-25 23:57:07 -05:00
2018-11-22 03:01:03 -05:00
describe " when user can not mention a group " do
2020-02-18 15:45:02 -05:00
it " should not create the mention with the notify class " do
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post , raw : " hello @ #{ group . name } " )
2018-11-25 23:57:07 -05:00
post . trigger_post_process
post . reload
2018-11-22 03:01:03 -05:00
expect ( post . cooked ) . to eq (
2020-02-18 15:45:02 -05:00
%Q|<p>hello <a class="mention-group" href="/groups/#{group.name}">@#{group.name}</a></p>| ,
2018-11-22 03:01:03 -05:00
)
end
end
describe " when user can mention a group " do
before { group . add ( post . user ) }
2019-07-08 17:12:09 -04:00
it " should create the mention " do
post . update! ( raw : " hello @ #{ group . name } " )
post . trigger_post_process
post . reload
expect ( post . cooked ) . to eq (
2020-02-18 15:45:02 -05:00
%Q|<p>hello <a class="mention-group notify" href="/groups/#{group.name}">@#{group.name}</a></p>| ,
2019-07-08 17:12:09 -04:00
)
end
end
describe " when group owner can mention a group " do
before do
group . update! ( mentionable_level : Group :: ALIAS_LEVELS [ :owners_mods_and_admins ] )
group . add_owner ( post . user )
end
2018-11-22 03:01:03 -05:00
it " should create the mention " do
post . update! ( raw : " hello @ #{ group . name } " )
2018-11-25 23:57:07 -05:00
post . trigger_post_process
post . reload
2018-11-22 03:01:03 -05:00
expect ( post . cooked ) . to eq (
2020-02-18 15:45:02 -05:00
%Q|<p>hello <a class="mention-group notify" href="/groups/#{group.name}">@#{group.name}</a></p>| ,
2018-11-22 03:01:03 -05:00
)
end
end
end
2014-01-15 11:34:17 -05:00
end
2014-02-26 23:43:45 -05:00
describe " has_host_spam " do
2018-06-19 12:15:27 -04:00
let ( :raw ) do
" hello from my site http://www.example.net http:// #{ GlobalSetting . hostname } http:// #{ RailsMultisite :: ConnectionManagement . current_hostname } "
2023-01-09 06:18:21 -05:00
end
2017-08-10 17:18:57 -04:00
2014-02-26 23:43:45 -05:00
it " correctly detects host spam " do
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post , raw : raw )
2014-02-26 23:43:45 -05:00
2018-06-19 12:15:27 -04:00
expect ( post . total_hosts_usage ) . to eq ( " www.example.net " = > 1 )
2014-02-26 23:43:45 -05:00
post . acting_user . trust_level = 0
2015-01-05 11:04:23 -05:00
expect ( post . has_host_spam? ) . to eq ( false )
2014-02-26 23:43:45 -05:00
2014-05-27 22:30:43 -04:00
SiteSetting . newuser_spam_host_threshold = 1
2014-02-26 23:43:45 -05:00
2015-01-05 11:04:23 -05:00
expect ( post . has_host_spam? ) . to eq ( true )
2014-02-26 23:43:45 -05:00
2020-07-26 20:23:54 -04:00
SiteSetting . allowed_spam_host_domains = " bla.com|boo.com | example.net "
2015-01-05 11:04:23 -05:00
expect ( post . has_host_spam? ) . to eq ( false )
2017-08-10 17:18:57 -04:00
end
it " doesn't punish staged users " do
SiteSetting . newuser_spam_host_threshold = 1
user = Fabricate ( :user , staged : true , trust_level : 0 )
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post , raw : raw , user : user )
2017-08-10 17:18:57 -04:00
expect ( post . has_host_spam? ) . to eq ( false )
end
2018-06-19 12:41:10 -04:00
it " punishes previously staged users that were created within 1 day " do
2018-06-15 13:45:53 -04:00
SiteSetting . newuser_spam_host_threshold = 1
2018-06-18 20:05:04 -04:00
SiteSetting . newuser_max_links = 3
2018-06-15 13:45:53 -04:00
user = Fabricate ( :user , staged : true , trust_level : 0 )
2018-06-18 20:05:04 -04:00
user . created_at = 1 . hour . ago
2020-03-17 11:48:24 -04:00
user . unstage!
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post , raw : raw , user : user )
2018-06-18 20:05:04 -04:00
expect ( post . has_host_spam? ) . to eq ( true )
end
2018-06-19 12:41:10 -04:00
it " doesn't punish previously staged users over 1 day old " do
2018-06-18 20:05:04 -04:00
SiteSetting . newuser_spam_host_threshold = 1
SiteSetting . newuser_max_links = 3
user = Fabricate ( :user , staged : true , trust_level : 0 )
2020-03-10 17:13:17 -04:00
user . created_at = 2 . days . ago
2020-03-17 11:48:24 -04:00
user . unstage!
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post , raw : raw , user : user )
2018-06-15 13:45:53 -04:00
expect ( post . has_host_spam? ) . to eq ( false )
end
2017-08-10 17:18:57 -04:00
it " ignores private messages " do
SiteSetting . newuser_spam_host_threshold = 1
user = Fabricate ( :user , trust_level : 0 )
2019-05-08 23:28:28 -04:00
post =
Fabricate ( :post , raw : raw , user : user , topic : Fabricate ( :private_message_topic , user : user ) )
2017-08-10 17:18:57 -04:00
expect ( post . has_host_spam? ) . to eq ( false )
2014-02-26 23:43:45 -05:00
end
end
2014-04-25 09:14:05 -04:00
it " has custom fields " do
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post )
2015-01-05 11:04:23 -05:00
expect ( post . custom_fields [ " a " ] ) . to eq ( nil )
2014-04-25 09:14:05 -04:00
post . custom_fields [ " Tommy " ] = " Hanks "
post . custom_fields [ " Vincent " ] = " Vega "
post . save
post = Post . find ( post . id )
2015-01-05 11:04:23 -05:00
expect ( post . custom_fields ) . to eq ( " Tommy " = > " Hanks " , " Vincent " = > " Vega " )
2014-04-25 09:14:05 -04:00
end
2020-05-23 00:56:13 -04:00
describe " # excerpt_for_topic " do
it " returns a topic excerpt, defaulting to 220 chars " do
expected_excerpt =
" This is a sample post with semi-long raw content. The raw content is also more than \n two hundred characters to satisfy any test conditions that require content longer \n than the typical test post raw content. It really is… "
post = Fabricate ( :post_with_long_raw_content )
post . rebake!
excerpt = post . excerpt_for_topic
expect ( excerpt ) . to eq ( expected_excerpt )
end
it " respects the site setting for topic excerpt " do
SiteSetting . topic_excerpt_maxlength = 10
expected_excerpt = " This is a … "
post = Fabricate ( :post_with_long_raw_content )
post . rebake!
excerpt = post . excerpt_for_topic
expect ( excerpt ) . to eq ( expected_excerpt )
end
end
2014-05-27 22:30:43 -04:00
describe " # rebake! " do
it " will rebake a post correctly " do
post = create_post
2015-01-05 11:04:23 -05:00
expect ( post . baked_at ) . not_to eq ( nil )
2014-05-27 22:30:43 -04:00
first_baked = post . baked_at
first_cooked = post . cooked
2018-06-19 02:13:14 -04:00
DB . exec ( " UPDATE posts SET cooked = 'frogs' WHERE id = ? " , [ post . id ] )
2014-05-27 22:30:43 -04:00
post . reload
2014-09-22 12:55:13 -04:00
post . expects ( :publish_change_to_clients! ) . with ( :rebaked )
2014-05-27 22:30:43 -04:00
result = post . rebake!
2020-03-26 11:32:41 -04:00
expect ( post . baked_at ) . not_to eq_time ( first_baked )
2015-01-05 11:04:23 -05:00
expect ( post . cooked ) . to eq ( first_cooked )
expect ( result ) . to eq ( true )
2014-05-27 22:30:43 -04:00
end
2020-05-23 00:56:13 -04:00
it " updates the topic excerpt at the same time if it is the OP " do
post = create_post
post . topic . update ( excerpt : " test " )
DB . exec ( " UPDATE posts SET cooked = 'frogs' WHERE id = ? " , [ post . id ] )
post . reload
result = post . rebake!
post . topic . reload
expect ( post . topic . excerpt ) . not_to eq ( " test " )
end
it " does not update the topic excerpt if the post is not the OP " do
post = create_post
post2 = create_post
post . topic . update ( excerpt : " test " )
result = post2 . rebake!
post . topic . reload
expect ( post . topic . excerpt ) . to eq ( " test " )
end
2020-06-01 01:04:16 -04:00
it " works with posts in deleted topics " do
post = create_post
post . topic . trash!
post . reload
post . rebake!
end
2022-05-20 07:09:50 -04:00
it " uses inline onebox cache by default " do
Jobs . run_immediately!
stub_request ( :get , " http://testonebox.com/vvf " ) . to_return ( status : 200 , body : << ~ HTML )
< html > < head >
< title > hello this is Testonebox ! < / title>
< / head>< / html >
HTML
post = create_post ( raw : << ~ POST ) . reload
hello inline onebox http : / / testonebox . com / vvf
POST
expect ( post . cooked ) . to include ( " hello this is Testonebox! " )
stub_request ( :get , " http://testonebox.com/vvf " ) . to_return ( status : 200 , body : << ~ HTML )
< html > < head >
< title > hello this is updated Testonebox ! < / title>
< / head>< / html >
HTML
post . rebake!
expect ( post . reload . cooked ) . to include ( " hello this is Testonebox! " )
ensure
InlineOneboxer . invalidate ( " http://testonebox.com/vvf " )
end
it " passing invalidate_oneboxes: true ignores inline onebox cache " do
Jobs . run_immediately!
stub_request ( :get , " http://testonebox.com/vvf22 " ) . to_return ( status : 200 , body : << ~ HTML )
< html > < head >
< title > hello this is Testonebox ! < / title>
< / head>< / html >
HTML
post = create_post ( raw : << ~ POST ) . reload
hello inline onebox http : / / testonebox . com / vvf22
POST
expect ( post . cooked ) . to include ( " hello this is Testonebox! " )
stub_request ( :get , " http://testonebox.com/vvf22 " ) . to_return ( status : 200 , body : << ~ HTML )
< html > < head >
< title > hello this is updated Testonebox ! < / title>
< / head>< / html >
HTML
post . rebake! ( invalidate_oneboxes : true )
expect ( post . reload . cooked ) . to include ( " hello this is updated Testonebox! " )
ensure
InlineOneboxer . invalidate ( " http://testonebox.com/vvf22 " )
end
2014-05-27 22:30:43 -04:00
end
2016-08-19 15:27:12 -04:00
describe " # set_owner " do
2023-11-09 17:47:59 -05:00
fab! ( :post )
2016-08-19 15:27:12 -04:00
it " will change owner of a post correctly " do
post . set_owner ( coding_horror , Discourse . system_user )
post . reload
expect ( post . user ) . to eq ( coding_horror )
expect ( post . revisions . size ) . to eq ( 1 )
end
it " skips creating new post revision if skip_revision is true " do
post . set_owner ( coding_horror , Discourse . system_user , true )
post . reload
expect ( post . user ) . to eq ( coding_horror )
expect ( post . revisions . size ) . to eq ( 0 )
end
2017-09-14 10:15:07 -04:00
it " uses default locale for edit reason " do
I18n . locale = " de "
post . set_owner ( coding_horror , Discourse . system_user )
post . reload
expected_reason =
I18n . with_locale ( SiteSetting . default_locale ) { I18n . t ( " change_owner.post_revision_text " ) }
expect ( post . edit_reason ) . to eq ( expected_reason )
end
2016-08-19 15:27:12 -04:00
end
2014-05-27 22:30:43 -04:00
describe " .rebake_old " do
it " will catch posts it needs to rebake " do
post = create_post
2014-05-30 00:45:39 -04:00
post . update_columns ( baked_at : Time . new ( 2000 , 1 , 1 ) , baked_version : - 1 )
2014-05-27 22:30:43 -04:00
Post . rebake_old ( 100 )
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . baked_at ) . to be > 1 . day . ago
2014-05-30 00:45:39 -04:00
baked = post . baked_at
Post . rebake_old ( 100 )
post . reload
2020-03-10 17:13:17 -04:00
expect ( post . baked_at ) . to eq_time ( baked )
2014-05-27 22:30:43 -04:00
end
2019-01-03 17:24:46 -05:00
it " will rate limit globally " do
post1 = create_post
post2 = create_post
post3 = create_post
Post . where ( id : [ post1 . id , post2 . id , post3 . id ] ) . update_all ( baked_version : - 1 )
global_setting :max_old_rebakes_per_15_minutes , 2
RateLimiter . clear_all_global!
RateLimiter . enable
Post . rebake_old ( 100 )
expect ( post3 . reload . baked_version ) . not_to eq ( - 1 )
expect ( post2 . reload . baked_version ) . not_to eq ( - 1 )
expect ( post1 . reload . baked_version ) . to eq ( - 1 )
end
2014-05-27 22:30:43 -04:00
end
2022-02-10 20:00:58 -05:00
describe " # hide! " do
2023-11-09 17:47:59 -05:00
fab! ( :post )
2022-02-10 20:00:58 -05:00
2021-01-11 14:56:08 -05:00
after { Discourse . redis . flushdb }
2023-08-17 22:55:17 -04:00
it " should not run post validations " do
PostValidator . any_instance . expects ( :validate ) . never
2022-02-10 20:00:58 -05:00
2023-08-17 22:55:17 -04:00
expect { post . hide! ( PostActionType . types [ :off_topic ] ) } . to change { post . reload . hidden } . from (
false ,
) . to ( true )
2022-02-10 20:00:58 -05:00
end
it " should decrease user_stat topic_count for first post " do
expect do post . hide! ( PostActionType . types [ :off_topic ] ) end . to change {
post . user . user_stat . reload . topic_count
} . from ( 1 ) . to ( 0 )
end
it " should decrease user_stat post_count " do
post_2 = Fabricate ( :post , topic : post . topic , user : post . user )
expect do post_2 . hide! ( PostActionType . types [ :off_topic ] ) end . to change {
post_2 . user . user_stat . reload . post_count
} . from ( 1 ) . to ( 0 )
2021-01-11 14:56:08 -05:00
end
end
2022-02-10 20:00:58 -05:00
describe " # unhide! " do
2023-11-09 17:47:59 -05:00
fab! ( :post )
2022-02-10 20:00:58 -05:00
2017-07-07 02:09:14 -04:00
before { SiteSetting . unique_posts_mins = 5 }
2014-08-11 04:48:00 -04:00
2014-11-12 10:34:30 -05:00
it " will unhide the first post & make the topic visible " do
hidden_topic = Fabricate ( :topic , visible : false )
post = create_post ( topic : hidden_topic )
2014-08-11 04:48:00 -04:00
post . update_columns ( hidden : true , hidden_at : Time . now , hidden_reason_id : 1 )
post . reload
2015-01-05 11:04:23 -05:00
expect ( post . hidden ) . to eq ( true )
2014-08-11 04:48:00 -04:00
2014-09-22 12:55:13 -04:00
post . expects ( :publish_change_to_clients! ) . with ( :acted )
2014-08-11 04:48:00 -04:00
post . unhide!
2014-11-12 10:34:30 -05:00
2014-08-11 04:48:00 -04:00
post . reload
2014-11-12 10:34:30 -05:00
hidden_topic . reload
2014-08-11 04:48:00 -04:00
2015-01-05 11:04:23 -05:00
expect ( post . hidden ) . to eq ( false )
expect ( hidden_topic . visible ) . to eq ( true )
2024-04-28 20:34:46 -04:00
expect ( hidden_topic . visibility_reason_id ) . to eq ( Topic . visibility_reasons [ :op_unhidden ] )
end
it " will not unhide the topic if the topic visibility_reason_id is not op_flag_threshold_reached " do
hidden_topic =
Fabricate (
:topic ,
visible : false ,
visibility_reason_id : Topic . visibility_reasons [ :manually_unlisted ] ,
)
post = create_post ( topic : hidden_topic )
post . update_columns ( hidden : true , hidden_at : Time . now , hidden_reason_id : 1 )
post . reload
expect ( post . hidden ) . to eq ( true )
post . unhide!
hidden_topic . reload
expect ( hidden_topic . visible ) . to eq ( false )
2014-08-11 04:48:00 -04:00
end
2022-02-10 20:00:58 -05:00
it " should increase user_stat topic_count for first post " do
post . hide! ( PostActionType . types [ :off_topic ] )
expect do post . unhide! end . to change { post . user . user_stat . reload . topic_count } . from ( 0 ) . to ( 1 )
end
it " should decrease user_stat post_count " do
post_2 = Fabricate ( :post , topic : post . topic , user : post . user )
post_2 . hide! ( PostActionType . types [ :off_topic ] )
expect do post_2 . unhide! end . to change { post_2 . user . user_stat . reload . post_count } . from ( 0 ) . to (
2023-01-09 06:18:21 -05:00
1 ,
2022-02-10 20:00:58 -05:00
)
end
2014-08-11 04:48:00 -04:00
end
2014-11-12 10:34:30 -05:00
it " will unhide the post but will keep the topic invisible/unlisted " do
hidden_topic = Fabricate ( :topic , visible : false )
2017-03-29 12:24:46 -04:00
create_post ( topic : hidden_topic )
2014-11-12 10:34:30 -05:00
second_post = create_post ( topic : hidden_topic )
second_post . update_columns ( hidden : true , hidden_at : Time . now , hidden_reason_id : 1 )
second_post . expects ( :publish_change_to_clients! ) . with ( :acted )
second_post . unhide!
second_post . reload
hidden_topic . reload
2015-01-05 11:04:23 -05:00
expect ( second_post . hidden ) . to eq ( false )
expect ( hidden_topic . visible ) . to eq ( false )
2014-11-12 10:34:30 -05:00
end
2018-05-28 19:34:12 -04:00
it " automatically orders post revisions by number ascending " do
2019-05-08 23:28:28 -04:00
post = Fabricate ( :post )
2018-05-28 19:34:12 -04:00
post . revisions . create! ( user_id : 1 , post_id : post . id , number : 2 )
post . revisions . create! ( user_id : 1 , post_id : post . id , number : 1 )
expect ( post . revisions . pluck ( :number ) ) . to eq ( [ 1 , 2 ] )
end
2023-03-09 11:26:47 -05:00
describe " video_thumbnails " do
fab! ( :video_upload ) { Fabricate ( :upload , extension : " mp4 " ) }
fab! ( :image_upload ) { Fabricate ( :upload ) }
fab! ( :image_upload_2 ) { Fabricate ( :upload ) }
let ( :base_url ) { " #{ Discourse . base_url_no_prefix } #{ Discourse . base_path } " }
let ( :video_url ) { " #{ base_url } #{ video_upload . url } " }
let ( :raw_video ) { << ~ RAW }
< video width = " 100% " height = " 100% " controls >
< source src = " #{ video_url } " >
< a href = " #{ video_url } " > #{video_url}</a>
< / video>
RAW
let ( :post ) { Fabricate ( :post , raw : raw_video ) }
2023-04-28 16:08:20 -04:00
before { SiteSetting . video_thumbnails_enabled = true }
2023-03-09 11:26:47 -05:00
it " has a topic thumbnail " do
# Thumbnails are tied to a specific video file by using the
# video's sha1 as the image filename
image_upload . original_filename = " #{ video_upload . sha1 } .png "
image_upload . save!
post . link_post_uploads
post . topic . reload
expect ( post . topic . topic_thumbnails . length ) . to eq ( 1 )
end
it " only applies for video uploads " do
image_upload . original_filename = " #{ image_upload_2 . sha1 } .png "
image_upload . save!
post . link_post_uploads
post . topic . reload
expect ( post . topic . topic_thumbnails . length ) . to eq ( 0 )
end
2023-04-21 15:33:33 -04:00
it " does not overwrite existing thumbnails " do
image_upload . original_filename = " #{ video_upload . sha1 } .png "
image_upload . save!
post . topic . image_upload_id = image_upload_2 . id
post . topic . save!
post . link_post_uploads
post . topic . reload
expect ( post . topic . image_upload_id ) . to eq ( image_upload_2 . id )
end
2023-04-28 16:08:20 -04:00
2023-05-23 11:00:09 -04:00
it " uses the newest thumbnail " do
image_upload . original_filename = " #{ video_upload . sha1 } .png "
image_upload . save!
image_upload_2 . original_filename = " #{ video_upload . sha1 } .png "
image_upload_2 . save!
post . link_post_uploads
post . topic . reload
expect ( post . topic . topic_thumbnails . length ) . to eq ( 1 )
expect ( post . topic . image_upload_id ) . to eq ( image_upload_2 . id )
end
2023-04-28 16:08:20 -04:00
it " does not create thumbnails when disabled " do
SiteSetting . video_thumbnails_enabled = false
image_upload . original_filename = " #{ video_upload . sha1 } .png "
image_upload . save!
post . link_post_uploads
post . topic . reload
expect ( post . topic . topic_thumbnails . length ) . to eq ( 0 )
end
2023-03-09 11:26:47 -05:00
end
2019-11-17 20:25:42 -05:00
describe " uploads " do
2019-05-28 21:00:25 -04:00
fab! ( :video_upload ) { Fabricate ( :upload , extension : " mp4 " ) }
2023-11-26 21:38:52 -05:00
fab! ( :video_upload_2 ) { Fabricate ( :upload , extension : " mp4 " ) }
2019-05-28 21:00:25 -04:00
fab! ( :image_upload ) { Fabricate ( :upload ) }
fab! ( :audio_upload ) { Fabricate ( :upload , extension : " ogg " ) }
fab! ( :attachment_upload ) { Fabricate ( :upload , extension : " csv " ) }
fab! ( :attachment_upload_2 ) { Fabricate ( :upload ) }
2019-06-18 21:10:50 -04:00
fab! ( :attachment_upload_3 ) { Fabricate ( :upload , extension : nil ) }
2018-09-05 21:58:01 -04:00
2020-10-09 07:51:24 -04:00
let ( :base_url ) { " #{ Discourse . base_url_no_prefix } #{ Discourse . base_path } " }
2019-05-03 15:46:20 -04:00
let ( :video_url ) { " #{ base_url } #{ video_upload . url } " }
2023-11-26 21:38:52 -05:00
let ( :video_2_url ) { " #{ base_url } #{ video_upload_2 . url } " }
2019-05-03 15:46:20 -04:00
let ( :audio_url ) { " #{ base_url } #{ audio_upload . url } " }
2019-11-17 20:25:42 -05:00
let ( :raw_multiple ) { << ~ RAW }
2018-09-05 21:58:01 -04:00
< a href = " #{ attachment_upload . url } " > Link < / a>
2019-05-28 21:00:25 -04:00
[ test | attachment ] ( #{attachment_upload_2.short_url})
2019-06-18 21:10:50 -04:00
[ test3 | attachment ] ( #{attachment_upload_3.short_url})
2018-09-05 21:58:01 -04:00
< img src = " #{ image_upload . url } " >
< video width = " 100% " height = " 100% " controls >
2019-05-03 15:46:20 -04:00
< source src = " #{ video_url } " >
< a href = " #{ video_url } " > #{video_url}</a>
2018-09-05 21:58:01 -04:00
< / video>
< audio controls >
2019-05-03 15:46:20 -04:00
< source src = " #{ audio_url } " >
< a href = " #{ audio_url } " > #{audio_url}</a>
2018-09-05 21:58:01 -04:00
< / audio>
2023-11-26 21:38:52 -05:00
< div class = " video-placeholder-container " data - video - src = " #{ video_2_url } " dir = " ltr " style = " cursor: pointer; " >
< div class = " video-placeholder-wrapper " >
< div class = " video-placeholder-overlay " >
< svg class = " fa d-icon d-icon-play svg-icon svg-string " xmlns = " http://www.w3.org/2000/svg " >
< use href = " # play " > < / use>
< / svg>
< / div>
< / div>
< / div>
2018-09-05 21:58:01 -04:00
RAW
2019-11-17 20:25:42 -05:00
let ( :post ) { Fabricate ( :post , raw : raw_multiple ) }
2018-09-05 21:58:01 -04:00
2020-06-19 11:45:08 -04:00
it " removes post uploads on destroy " do
post . link_post_uploads
post . trash!
2023-11-26 21:38:52 -05:00
expect ( UploadReference . count ) . to eq ( 7 )
2020-06-19 11:45:08 -04:00
post . destroy!
2022-06-08 19:24:30 -04:00
expect ( UploadReference . count ) . to eq ( 0 )
2020-06-19 11:45:08 -04:00
end
2022-07-27 06:21:10 -04:00
describe " # link_post_uploads " do
2019-11-17 20:25:42 -05:00
it " finds all the uploads in the post " do
post . link_post_uploads
2022-06-08 19:24:30 -04:00
expect ( UploadReference . where ( target : post ) . pluck ( :upload_id ) ) . to contain_exactly (
2019-11-17 20:25:42 -05:00
video_upload . id ,
2023-11-26 21:38:52 -05:00
video_upload_2 . id ,
2019-11-17 20:25:42 -05:00
image_upload . id ,
audio_upload . id ,
attachment_upload . id ,
attachment_upload_2 . id ,
attachment_upload_3 . id ,
)
end
2018-09-05 21:58:01 -04:00
2019-11-17 20:25:42 -05:00
it " cleans the reverse index up for the current post " do
post . link_post_uploads
2022-06-08 19:24:30 -04:00
post_uploads_ids = post . upload_references . pluck ( :id )
2019-11-17 20:25:42 -05:00
post . link_post_uploads
2022-06-08 19:24:30 -04:00
expect ( post . reload . upload_references . pluck ( :id ) ) . to_not contain_exactly ( post_uploads_ids )
2019-11-17 20:25:42 -05:00
end
2020-01-15 22:50:27 -05:00
2024-04-16 00:10:25 -04:00
context " when secure uploads is enabled " do
2020-09-14 07:32:25 -04:00
before do
setup_s3
SiteSetting . authorized_extensions = " pdf|png|jpg|csv "
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2020-09-14 07:32:25 -04:00
end
2020-01-15 22:50:27 -05:00
2024-04-16 00:10:25 -04:00
it " sets the access_control_post_id on uploads in the post that don't already have the value set " do
other_post = Fabricate ( :post )
video_upload . update ( access_control_post_id : other_post . id )
audio_upload . update ( access_control_post_id : other_post . id )
2020-01-15 22:50:27 -05:00
2024-04-16 00:10:25 -04:00
post . link_post_uploads
2024-04-15 20:37:57 -04:00
2024-04-16 00:10:25 -04:00
image_upload . reload
video_upload . reload
expect ( image_upload . access_control_post_id ) . to eq ( post . id )
expect ( video_upload . access_control_post_id ) . not_to eq ( post . id )
end
2020-02-13 20:17:09 -05:00
2024-04-16 00:10:25 -04:00
context " for custom emoji " do
before { CustomEmoji . create ( name : " meme " , upload : image_upload ) }
it " never sets an access control post because they should not be secure " do
2020-02-13 20:17:09 -05:00
post . link_post_uploads
2024-04-16 00:10:25 -04:00
expect ( image_upload . reload . access_control_post_id ) . to eq ( nil )
2020-02-13 20:17:09 -05:00
end
end
2020-01-15 22:50:27 -05:00
end
2018-09-05 21:58:01 -04:00
end
2022-07-27 06:21:10 -04:00
describe " # update_uploads_secure_status " do
2024-01-29 04:52:02 -05:00
fab! ( :user ) { Fabricate ( :user , trust_level : TrustLevel [ 0 ] ) }
2019-11-17 20:25:42 -05:00
let ( :raw ) { << ~ RAW }
< a href = " #{ attachment_upload . url } " > Link < / a>
< img src = " #{ image_upload . url } " >
RAW
2018-09-05 21:58:01 -04:00
2019-11-17 20:25:42 -05:00
before do
2021-06-21 12:15:24 -04:00
Jobs . run_immediately!
2020-09-14 07:32:25 -04:00
setup_s3
SiteSetting . authorized_extensions = " pdf|png|jpg|csv "
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2019-11-17 20:25:42 -05:00
2020-09-14 07:32:25 -04:00
attachment_upload . update! ( original_filename : " hello.csv " )
2019-11-17 20:25:42 -05:00
2020-09-14 07:32:25 -04:00
stub_upload ( attachment_upload )
stub_upload ( image_upload )
2019-11-17 20:25:42 -05:00
end
2018-09-05 21:58:01 -04:00
2022-09-28 19:24:33 -04:00
it " marks image and attachment uploads as secure in PMs when secure_uploads is ON " do
SiteSetting . secure_uploads = true
2019-11-17 20:25:42 -05:00
post =
Fabricate (
:post ,
raw : raw ,
user : user ,
topic : Fabricate ( :private_message_topic , user : user ) ,
)
post . link_post_uploads
2021-01-28 18:03:44 -05:00
post . update_uploads_secure_status ( source : " test " )
2019-11-17 20:25:42 -05:00
2022-06-08 19:24:30 -04:00
expect (
UploadReference . where ( target : post ) . joins ( :upload ) . pluck ( :upload_id , :secure ) ,
2020-03-25 17:16:02 -04:00
) . to contain_exactly ( [ attachment_upload . id , true ] , [ image_upload . id , true ] )
2019-11-17 20:25:42 -05:00
end
2022-09-28 19:24:33 -04:00
it " marks image uploads as not secure in PMs when when secure_uploads is ON " do
SiteSetting . secure_uploads = false
2019-11-17 20:25:42 -05:00
post =
Fabricate (
:post ,
raw : raw ,
user : user ,
topic : Fabricate ( :private_message_topic , user : user ) ,
)
post . link_post_uploads
2021-01-28 18:03:44 -05:00
post . update_uploads_secure_status ( source : " test " )
2019-11-17 20:25:42 -05:00
2022-06-08 19:24:30 -04:00
expect (
UploadReference . where ( target : post ) . joins ( :upload ) . pluck ( :upload_id , :secure ) ,
2019-11-17 20:25:42 -05:00
) . to contain_exactly ( [ attachment_upload . id , false ] , [ image_upload . id , false ] )
end
it " marks attachments as secure when relevant setting is enabled " do
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2020-02-20 19:01:32 -05:00
private_category = Fabricate ( :private_category , group : Fabricate ( :group ) )
post =
Fabricate (
:post ,
raw : raw ,
user : user ,
topic : Fabricate ( :topic , user : user , category : private_category ) ,
)
2019-11-17 20:25:42 -05:00
post . link_post_uploads
2021-01-28 18:03:44 -05:00
post . update_uploads_secure_status ( source : " test " )
2019-11-17 20:25:42 -05:00
2022-06-08 19:24:30 -04:00
expect (
UploadReference . where ( target : post ) . joins ( :upload ) . pluck ( :upload_id , :secure ) ,
2019-11-17 20:25:42 -05:00
) . to contain_exactly ( [ attachment_upload . id , true ] , [ image_upload . id , true ] )
end
it " does not mark an upload as secure if it has already been used in a public topic " do
post = Fabricate ( :post , raw : raw , user : user , topic : Fabricate ( :topic , user : user ) )
post . link_post_uploads
2021-01-28 18:03:44 -05:00
post . update_uploads_secure_status ( source : " test " )
2019-11-17 20:25:42 -05:00
pm =
Fabricate (
:post ,
raw : raw ,
user : user ,
topic : Fabricate ( :private_message_topic , user : user ) ,
)
pm . link_post_uploads
2021-01-28 18:03:44 -05:00
pm . update_uploads_secure_status ( source : " test " )
2019-11-17 20:25:42 -05:00
2022-06-08 19:24:30 -04:00
expect (
UploadReference . where ( target : pm ) . joins ( :upload ) . pluck ( :upload_id , :secure ) ,
2019-11-17 20:25:42 -05:00
) . to contain_exactly ( [ attachment_upload . id , false ] , [ image_upload . id , false ] )
end
2018-09-05 21:58:01 -04:00
end
end
2022-07-27 12:14:14 -04:00
describe " topic updated_at " do
2019-03-28 02:28:01 -04:00
let :topic do
create_post . topic
end
def updates_topic_updated_at
2020-03-10 17:13:17 -04:00
time = freeze_time 1 . day . from_now
2019-03-28 02:28:01 -04:00
result = yield
topic . reload
expect ( topic . updated_at ) . to eq_time ( time )
result
end
it " will update topic updated_at for all topic related events " do
2022-12-16 11:42:51 -05:00
SiteSetting . whispers_allowed_groups = " #{ Group :: AUTO_GROUPS [ :staff ] } "
2019-03-28 02:28:01 -04:00
post =
updates_topic_updated_at do
create_post ( topic_id : topic . id , post_type : Post . types [ :whisper ] )
end
updates_topic_updated_at { PostDestroyer . new ( Discourse . system_user , post ) . destroy }
updates_topic_updated_at { PostDestroyer . new ( Discourse . system_user , post ) . recover }
end
end
2022-07-27 12:14:14 -04:00
describe " have_uploads " do
2019-04-14 16:24:55 -04:00
it " should find all posts with the upload " do
ids = [ ]
2019-12-18 00:51:57 -05:00
ids << Fabricate (
:post ,
cooked : " A post with upload <img src='/ #{ upload_path } /1/defghijklmno.png'> " ,
) . id
ids << Fabricate (
:post ,
cooked :
" A post with optimized image <img src='/ #{ upload_path } /_optimized/601/961/defghijklmno.png'> " ,
) . id
2019-05-08 23:28:28 -04:00
Fabricate ( :post )
2019-12-18 00:51:57 -05:00
ids << Fabricate (
:post ,
cooked : " A post with upload <img src='/ #{ upload_path } /original/1X/abc/defghijklmno.png'> " ,
) . id
2019-05-08 23:28:28 -04:00
ids << Fabricate (
:post ,
cooked :
" A post with upload link <a href='https://cdn.example.com/original/1X/abc/defghijklmno.png'> " ,
) . id
ids << Fabricate (
:post ,
cooked :
" A post with optimized image <img src='https://cdn.example.com/bucket/optimized/1X/abc/defghijklmno.png'> " ,
) . id
Fabricate (
:post ,
cooked :
" A post with external link <a href='https://example.com/wp-content/uploads/abcdef.gif'> " ,
)
2019-05-16 07:09:38 -04:00
ids << Fabricate (
:post ,
cooked :
'A post with missing upload <img src="https://cdn.example.com/images/transparent.png" data-orig-src="upload://defghijklmno.png">' ,
) . id
2019-09-24 13:47:59 -04:00
ids << Fabricate (
:post ,
cooked :
'A post with video upload <video width="100%" height="100%" controls=""><source src="https://cdn.example.com/uploads/short-url/XefghijklmU9.mp4"><a href="https://cdn.example.com/uploads/short-url/XefghijklmU9.mp4">https://cdn.example.com/uploads/short-url/XefghijklmU9.mp4</a></video>' ,
) . id
2019-04-14 16:24:55 -04:00
expect ( Post . have_uploads . order ( :id ) . pluck ( :id ) ) . to eq ( ids )
end
end
2019-06-11 10:25:02 -04:00
describe " # each_upload_url " do
it " correctly identifies all upload urls " do
2019-09-22 06:02:28 -04:00
SiteSetting . authorized_extensions = " * "
2019-06-11 10:25:02 -04:00
upload1 = Fabricate ( :upload )
upload2 = Fabricate ( :upload )
2019-09-22 06:02:28 -04:00
upload3 = Fabricate ( :video_upload )
2019-10-14 03:19:11 -04:00
upload4 = Fabricate ( :upload )
2020-03-10 09:01:40 -04:00
upload5 = Fabricate ( :upload )
upload6 = Fabricate ( :video_upload )
upload7 = Fabricate ( :upload , extension : " vtt " )
2023-11-26 21:38:52 -05:00
upload8 = Fabricate ( :video_upload )
2019-07-30 22:00:52 -04:00
set_cdn_url " https://awesome.com/somepath "
post = Fabricate ( :post , raw : << ~ RAW )
2019-09-22 06:02:28 -04:00
A post with image , video and link upload .
2019-07-30 22:00:52 -04:00
! [ ] ( #{upload1.short_url})
2019-10-14 03:19:11 -04:00
" #{ GlobalSetting . cdn_url } #{ upload4 . url } "
2019-07-30 22:00:52 -04:00
< a href = '#{Discourse.base_url}#{upload2.url}' > Link to upload < / a>
! [ ] ( http : / /ex ample . com / external . png )
2019-09-22 06:02:28 -04:00
#{Discourse.base_url}#{upload3.short_path}
2020-03-10 09:01:40 -04:00
< video poster = " #{ Discourse . base_url } #{ upload5 . url } " >
< source src = " #{ Discourse . base_url } #{ upload6 . url } " type = " video/mp4 " / >
< track src = " #{ Discourse . base_url } #{ upload7 . url } " label = " English " kind = " subtitles " srclang = " en " default / >
< / video>
2023-11-26 21:38:52 -05:00
< div class = " video-placeholder-container " data - video - src = " #{ Discourse . base_url } #{ upload8 . url } " dir = " ltr " style = " cursor: pointer; " >
< div class = " video-placeholder-wrapper " >
< div class = " video-placeholder-overlay " >
< svg class = " fa d-icon d-icon-play svg-icon svg-string " xmlns = " http://www.w3.org/2000/svg " >
< use href = " # play " > < / use>
< / svg>
< / div>
< / div>
< / div>
2019-07-30 22:00:52 -04:00
RAW
urls = [ ]
paths = [ ]
post . each_upload_url do | src , path , _ |
urls << src
paths << path
end
expect ( urls ) . to contain_exactly (
" #{ GlobalSetting . cdn_url } #{ upload1 . url } " ,
2019-10-14 03:19:11 -04:00
" #{ GlobalSetting . cdn_url } #{ upload4 . url } " ,
2019-09-22 06:02:28 -04:00
" #{ Discourse . base_url } #{ upload2 . url } " ,
2020-03-10 09:01:40 -04:00
" #{ Discourse . base_url } #{ upload3 . short_path } " ,
" #{ Discourse . base_url } #{ upload5 . url } " ,
" #{ Discourse . base_url } #{ upload6 . url } " ,
" #{ Discourse . base_url } #{ upload7 . url } " ,
2023-11-26 21:38:52 -05:00
" #{ Discourse . base_url } #{ upload8 . url } " ,
2019-07-30 22:00:52 -04:00
)
expect ( paths ) . to contain_exactly (
upload1 . url ,
2019-10-14 03:19:11 -04:00
upload4 . url ,
2019-09-22 06:02:28 -04:00
upload2 . url ,
2020-03-10 09:01:40 -04:00
nil ,
upload5 . url ,
upload6 . url ,
upload7 . url ,
2023-11-26 21:38:52 -05:00
upload8 . url ,
2019-07-30 22:00:52 -04:00
)
2019-06-11 10:25:02 -04:00
end
2020-08-10 12:59:29 -04:00
it " correctly identifies secure uploads " do
2020-09-14 07:32:25 -04:00
setup_s3
SiteSetting . authorized_extensions = " pdf|png|jpg|csv "
2022-09-28 19:24:33 -04:00
SiteSetting . secure_uploads = true
2020-09-14 07:32:25 -04:00
2020-08-10 12:59:29 -04:00
upload1 = Fabricate ( :upload_s3 , secure : true )
upload2 = Fabricate ( :upload_s3 , secure : true )
# Test including domain:
upload1_url = UrlHelper . cook_url ( upload1 . url , secure : true )
# Test without domain:
upload2_path = URI . parse ( UrlHelper . cook_url ( upload2 . url , secure : true ) ) . path
post = Fabricate ( :post , raw : << ~ RAW )
< img src = " #{ upload1_url } " / >
< img src = " #{ upload2_path } " / >
RAW
sha1s = [ ]
post . each_upload_url { | src , path , sha | sha1s << sha }
expect ( sha1s ) . to contain_exactly ( upload1 . sha1 , upload2 . sha1 )
end
2019-09-02 05:41:22 -04:00
it " correctly identifies missing uploads with short url " do
upload = Fabricate ( :upload )
url = upload . short_url
sha1 = upload . sha1
upload . destroy!
post = Fabricate ( :post , raw : " ![upload]( #{ url } ) " )
urls = [ ]
paths = [ ]
sha1s = [ ]
2019-09-02 06:49:20 -04:00
post . each_upload_url do | src , path , sha |
2019-09-02 05:41:22 -04:00
urls << src
paths << path
2019-09-02 06:49:20 -04:00
sha1s << sha
2019-09-02 05:41:22 -04:00
end
expect ( urls ) . to contain_exactly ( url )
expect ( paths ) . to contain_exactly ( nil )
expect ( sha1s ) . to contain_exactly ( sha1 )
end
2019-06-11 10:25:02 -04:00
it " should skip external urls with upload url in query string " do
2020-09-14 07:32:25 -04:00
setup_s3
2019-06-11 10:25:02 -04:00
urls = [ ]
upload = Fabricate ( :upload_s3 )
post =
Fabricate (
:post ,
raw :
" <a href='https://link.example.com/redirect?url= #{ Discourse . store . cdn_url ( upload . url ) } '>Link to upload</a> " ,
)
post . each_upload_url { | src , _ , _ | urls << src }
expect ( urls ) . to be_empty
end
2021-10-01 02:55:17 -04:00
2024-05-23 01:15:16 -04:00
it " should skip external URLs following the `/uploads/short-url` pattern if a host is present and the host is not the configured host " do
upload = Fabricate ( :upload )
raw = << ~ RAW
[ Upload link with Discourse . base_url ] ( #{Discourse.base_url}/uploads/short-url/#{upload.sha1}.#{upload.extension})
[ Upload link without Discourse . base_url ] ( https : / /some . other . host / uploads / short - url / #{upload.sha1}.#{upload.extension})
[ Upload link without host ] ( / uploads /s hort - url / #{upload.sha1}.#{upload.extension})
RAW
post = Fabricate ( :post , raw : raw )
urls = [ ]
post . each_upload_url { | src , _ , _ | urls << src }
expect ( urls ) . to contain_exactly (
" #{ Discourse . base_url } /uploads/short-url/ #{ upload . sha1 } . #{ upload . extension } " ,
" /uploads/short-url/ #{ upload . sha1 } . #{ upload . extension } " ,
)
end
2021-10-01 02:55:17 -04:00
it " skip S3 cdn urls with different path " do
setup_s3
SiteSetting . Upload . stubs ( :s3_cdn_url ) . returns ( " https://cdn.example.com/site1 " )
urls = [ ]
raw =
" <img src='https://cdn.example.com/site1/original/1X/bc68acbc8c022726e69f980e00d6811212r.jpg' /><img src='https://cdn.example.com/site2/original/1X/bc68acbc8c022726e69f980e00d68112128.jpg' /> "
post = Fabricate ( :post , raw : raw )
post . each_upload_url { | src , _ , _ | urls << src }
expect ( urls ) . to contain_exactly (
" https://cdn.example.com/site1/original/1X/bc68acbc8c022726e69f980e00d6811212r.jpg " ,
)
end
2019-06-11 10:25:02 -04:00
end
2021-03-03 16:33:58 -05:00
describe " # publish_changes_to_client! " do
fab! ( :user1 ) { Fabricate ( :user ) }
fab! ( :user3 ) { Fabricate ( :user ) }
fab! ( :topic ) { Fabricate ( :private_message_topic , user : user1 ) }
fab! ( :post ) { Fabricate ( :post , topic : topic ) }
fab! ( :group_user ) { Fabricate ( :group_user , user : user3 ) }
fab! ( :topic_allowed_group ) do
Fabricate ( :topic_allowed_group , topic : topic , group : group_user . group )
2023-01-09 06:18:21 -05:00
end
2021-03-03 16:33:58 -05:00
let ( :user2 ) { topic . allowed_users . last }
it " send message to all users participating in private conversation " do
freeze_time
message = {
id : post . id ,
post_number : post . post_number ,
updated_at : Time . now ,
user_id : post . user_id ,
last_editor_id : post . last_editor_id ,
type : :created ,
version : post . version ,
}
2022-06-27 17:21:05 -04:00
messages =
MessageBus . track_publish ( " /topic/ #{ topic . id } " ) { post . publish_change_to_clients! ( :created ) }
created_message = messages . select { | msg | msg . data [ :type ] == :created } . first
expect ( created_message ) . to be_present
expect ( created_message . data ) . to eq ( message )
expect ( created_message . user_ids . sort ) . to eq ( [ user1 . id , user2 . id , user3 . id ] . sort )
stats_message = messages . select { | msg | msg . data [ :type ] == :created } . first
expect ( stats_message ) . to be_present
expect ( stats_message . user_ids . sort ) . to eq ( [ user1 . id , user2 . id , user3 . id ] . sort )
end
it " also publishes topic stats " do
messages =
MessageBus . track_publish ( " /topic/ #{ topic . id } " ) { post . publish_change_to_clients! ( :created ) }
stats_message = messages . select { | msg | msg . data [ :type ] == :stats } . first
expect ( stats_message ) . to be_present
end
it " skips publishing topic stats when requested " do
messages =
MessageBus . track_publish ( " /topic/ #{ topic . id } " ) do
post . publish_change_to_clients! ( :anything , { skip_topic_stats : true } )
end
stats_message = messages . select { | msg | msg . data [ :type ] == :stats } . first
expect ( stats_message ) . to be_blank
# ensure that :skip_topic_stats did not get merged with the message
other_message = messages . select { | msg | msg . data [ :type ] == :anything } . first
expect ( other_message ) . to be_present
expect ( other_message . data . key? ( :skip_topic_stats ) ) . to be_falsey
2021-03-03 16:33:58 -05:00
end
end
2021-10-26 11:31:15 -04:00
describe " # cannot_permanently_delete_reason " do
2023-11-09 17:47:59 -05:00
fab! ( :post )
fab! ( :admin )
2021-10-26 11:31:15 -04:00
before do
freeze_time
PostDestroyer . new ( admin , post ) . destroy
end
it " returns error message if same admin and time did not pass " do
expect ( post . cannot_permanently_delete_reason ( admin ) ) . to eq (
I18n . t (
" post.cannot_permanently_delete.wait_or_different_admin " ,
time_left : RateLimiter . time_left ( Post :: PERMANENT_DELETE_TIMER . to_i ) ,
2023-01-09 06:18:21 -05:00
) ,
2021-10-26 11:31:15 -04:00
)
end
it " returns nothing if different admin " do
expect ( post . cannot_permanently_delete_reason ( Fabricate ( :admin ) ) ) . to eq ( nil )
end
end
2022-03-15 05:17:06 -04:00
describe " # canonical_url " do
it " is able to determine correct canonical urls " do
# ugly, but no interface to set this and we don't want to create
# 100 posts to test this thing
TopicView . stubs ( :chunk_size ) . returns ( 2 )
post1 = Fabricate ( :post )
topic = post1 . topic
post2 = Fabricate ( :post , topic : topic )
post3 = Fabricate ( :post , topic : topic )
post4 = Fabricate ( :post , topic : topic )
topic_url = post1 . topic . url
expect ( post1 . canonical_url ) . to eq ( " #{ topic_url } # post_ #{ post1 . post_number } " )
expect ( post2 . canonical_url ) . to eq ( " #{ topic_url } # post_ #{ post2 . post_number } " )
expect ( post3 . canonical_url ) . to eq ( " #{ topic_url } ?page=2 # post_ #{ post3 . post_number } " )
expect ( post4 . canonical_url ) . to eq ( " #{ topic_url } ?page=2 # post_ #{ post4 . post_number } " )
end
end
2023-09-05 01:47:18 -04:00
2023-11-12 22:06:25 -05:00
describe " relative_url " do
it " returns the correct post url with subfolder install " do
set_subfolder " /forum "
post = Fabricate ( :post )
expect ( post . relative_url ) . to eq (
" /forum/t/ #{ post . topic . slug } / #{ post . topic . id } / #{ post . post_number } " ,
)
end
end
2024-07-09 04:42:38 -04:00
describe " full_url " do
it " returns the correct post url with subfolder install " do
set_subfolder " /forum "
post = Fabricate ( :post )
expect ( post . full_url ) . to eq (
" #{ Discourse . base_url_no_prefix } /forum/t/ #{ post . topic . slug } / #{ post . topic . id } / #{ post . post_number } " ,
)
end
end
2023-09-05 01:47:18 -04:00
describe " public_posts_count_per_day " do
before do
2024-02-29 19:07:35 -05:00
freeze_time_safe
2023-09-05 01:47:18 -04:00
Fabricate ( :post )
Fabricate ( :post , created_at : 1 . day . ago )
Fabricate ( :post , created_at : 1 . day . ago )
Fabricate ( :post , created_at : 2 . days . ago )
Fabricate ( :post , created_at : 4 . days . ago )
end
let ( :listable_topics_count_per_day ) do
{ 1 . day . ago . to_date = > 2 , 2 . days . ago . to_date = > 1 , Time . now . utc . to_date = > 1 }
end
it " collect closed interval public post count " do
expect ( Post . public_posts_count_per_day ( 2 . days . ago , Time . now ) ) . to include (
listable_topics_count_per_day ,
)
expect ( Post . public_posts_count_per_day ( 2 . days . ago , Time . now ) ) . not_to include (
4 . days . ago . to_date = > 1 ,
)
end
it " returns the correct number of public posts per day when there are no public posts " do
Fabricate ( :post , post_type : Post . types [ :whisper ] , created_at : 6 . days . ago )
Fabricate ( :post , post_type : Post . types [ :whisper ] , created_at : 7 . days . ago )
expect ( Post . public_posts_count_per_day ( 10 . days . ago , 5 . days . ago ) ) . to be_empty
end
2023-09-26 12:26:47 -04:00
it " returns the correct number of public posts per day with category filter " do
category = Fabricate ( :category )
another_category = Fabricate ( :category )
topic = Fabricate ( :topic , category : category )
another_topic = Fabricate ( :topic , category : another_category )
Fabricate ( :post , topic : topic , created_at : 6 . days . ago )
Fabricate ( :post , topic : topic , created_at : 7 . days . ago )
Fabricate ( :post , topic : another_topic , created_at : 6 . days . ago )
Fabricate ( :post , topic : another_topic , created_at : 7 . days . ago )
expect ( Post . public_posts_count_per_day ( 10 . days . ago , 5 . days . ago , category . id ) ) . to eq (
6 . days . ago . to_date = > 1 ,
7 . days . ago . to_date = > 1 ,
)
expect (
Post . public_posts_count_per_day (
10 . days . ago ,
5 . days . ago ,
[ category . id , another_category . id ] ,
) ,
) . to eq ( 6 . days . ago . to_date = > 2 , 7 . days . ago . to_date = > 2 )
end
2023-09-05 01:47:18 -04:00
it " returns the correct number of public posts per day with group filter " do
user = Fabricate ( :user )
group_user = Fabricate ( :user )
group = Fabricate ( :group )
group . add ( group_user )
Fabricate ( :post , user : user , created_at : 6 . days . ago )
Fabricate ( :post , user : user , created_at : 7 . days . ago )
Fabricate ( :post , user : group_user , created_at : 6 . days . ago )
Fabricate ( :post , user : group_user , created_at : 7 . days . ago )
expect (
Post . public_posts_count_per_day ( 10 . days . ago , 5 . days . ago , nil , false , [ group . id ] ) ,
) . to eq ( 6 . days . ago . to_date = > 1 , 7 . days . ago . to_date = > 1 )
end
end
2013-02-05 14:16:51 -05:00
end