2019-04-29 20:27:42 -04:00
# frozen_string_literal: true
2022-07-27 22:27:38 -04:00
RSpec . shared_examples 'finding and showing post' do
2019-05-08 05:56:02 -04:00
let! ( :post ) { post_by_user }
2018-05-22 17:39:05 -04:00
it " ensures the user can't see the post " do
topic = post . topic
topic . convert_to_private_message ( Discourse . system_user )
topic . remove_allowed_user ( Discourse . system_user , user . username )
get url
expect ( response ) . to be_forbidden
end
it 'succeeds' do
get url
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
2022-03-08 11:39:52 -05:00
it " returns 404 when post's topic is deleted " do
post . topic . destroy!
get url
expect ( response . status ) . to eq ( 404 )
end
2018-05-22 17:39:05 -04:00
context " deleted post " do
before do
post . trash! ( user )
end
it " can't find deleted posts as an anonymous user " do
get url
expect ( response . status ) . to eq ( 404 )
end
it " can't find deleted posts as a regular user " do
sign_in ( user )
get url
expect ( response . status ) . to eq ( 404 )
end
it " can find posts as a moderator " do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
get url
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
it " can find posts as a admin " do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
get url
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
2020-11-05 12:18:26 -05:00
context " category group moderator " do
fab! ( :group_user ) { Fabricate ( :group_user ) }
let ( :user_gm ) { group_user . user }
let ( :group ) { group_user . group }
before do
SiteSetting . enable_category_group_moderation = true
sign_in ( user_gm )
end
it " can find posts in the allowed category " do
post . topic . category . update! ( reviewable_by_group_id : group . id , topic_id : topic . id )
get url
expect ( response . status ) . to eq ( 200 )
end
it " can't find posts outside of the allowed category " do
get url
expect ( response . status ) . to eq ( 404 )
end
end
2018-05-22 17:39:05 -04:00
end
end
2022-07-27 22:27:38 -04:00
RSpec . shared_examples 'action requires login' do | method , url , params = { } |
2018-05-22 17:39:05 -04:00
it 'raises an exception when not logged in' do
2021-09-27 08:45:05 -04:00
self . public_send ( method , url , ** params )
2018-05-22 17:39:05 -04:00
expect ( response . status ) . to eq ( 403 )
end
end
2022-07-27 22:27:38 -04:00
RSpec . describe PostsController do
2019-05-06 05:36:54 -04:00
fab! ( :admin ) { Fabricate ( :admin ) }
2019-05-06 06:37:30 -04:00
fab! ( :moderator ) { Fabricate ( :moderator ) }
2019-05-06 23:12:20 -04:00
fab! ( :user ) { Fabricate ( :user ) }
2021-08-05 05:38:39 -04:00
fab! ( :user_trust_level_0 ) { Fabricate ( :trust_level_0 ) }
fab! ( :user_trust_level_1 ) { Fabricate ( :trust_level_1 ) }
2019-05-06 23:12:20 -04:00
fab! ( :category ) { Fabricate ( :category ) }
fab! ( :topic ) { Fabricate ( :topic ) }
2019-05-08 05:56:02 -04:00
fab! ( :post_by_user ) { Fabricate ( :post , user : user ) }
2017-08-31 00:06:56 -04:00
let ( :public_post ) { Fabricate ( :post , user : user , topic : topic ) }
2018-05-22 17:39:05 -04:00
let ( :topicless_post ) { Fabricate ( :post , user : user , raw : '<p>Car 54, where are you?</p>' ) }
let ( :private_topic ) do
2018-06-05 03:29:17 -04:00
Fabricate ( :topic , archetype : Archetype . private_message , category_id : nil )
2018-05-22 17:39:05 -04:00
end
let ( :private_post ) { Fabricate ( :post , user : user , topic : private_topic ) }
describe '#show' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/ #{ post . id } .json " }
end
it 'gets all the expected fields' do
# non fabricated test
new_post = create_post
get " /posts/ #{ new_post . id } .json "
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( parsed [ " topic_slug " ] ) . to eq ( new_post . topic . slug )
expect ( parsed [ " moderator " ] ) . to eq ( false )
expect ( parsed [ " username " ] ) . to eq ( new_post . user . username )
expect ( parsed [ " cooked " ] ) . to eq ( new_post . cooked )
end
end
describe '#by_number' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/by_number/ #{ post . topic_id } / #{ post . post_number } .json " }
end
end
2018-07-19 10:00:13 -04:00
describe '#by_date' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/by-date/ #{ post . topic_id } / #{ post . created_at . strftime ( " %Y-%m-%d " ) } .json " }
end
it 'returns the expected post' do
first_post = Fabricate ( :post , created_at : 10 . days . ago )
second_post = Fabricate ( :post , topic : first_post . topic , created_at : 4 . days . ago )
2019-04-29 18:41:17 -04:00
_third_post = Fabricate ( :post , topic : first_post . topic , created_at : 3 . days . ago )
2018-07-19 10:00:13 -04:00
get " /posts/by-date/ #{ second_post . topic_id } / #{ ( second_post . created_at - 2 . days ) . strftime ( " %Y-%m-%d " ) } .json "
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-07-19 10:00:13 -04:00
expect ( response . status ) . to eq ( 200 )
expect ( json [ " id " ] ) . to eq ( second_post . id )
end
it 'returns no post if date is > at last created post' do
get " /posts/by-date/ #{ post . topic_id } /2245-11-11.json "
2020-05-07 11:04:12 -04:00
_json = response . parsed_body
2018-07-19 10:00:13 -04:00
expect ( response . status ) . to eq ( 404 )
end
end
2018-05-22 17:39:05 -04:00
describe '#reply_history' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/ #{ post . id } /reply-history.json " }
end
2020-07-26 20:23:54 -04:00
it " returns the replies with allowlisted user custom fields " do
2018-11-13 12:16:50 -05:00
parent = Fabricate ( :post )
child = Fabricate ( :post , topic : parent . topic , reply_to_post_number : parent . post_number )
parent . user . upsert_custom_fields ( hello : 'world' , hidden : 'dontshow' )
SiteSetting . public_user_custom_fields = 'hello'
get " /posts/ #{ child . id } /reply-history.json "
2018-05-22 17:39:05 -04:00
expect ( response . status ) . to eq ( 200 )
2018-11-13 12:16:50 -05:00
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-11-13 12:16:50 -05:00
expect ( json [ 0 ] [ 'id' ] ) . to eq ( parent . id )
expect ( json [ 0 ] [ 'user_custom_fields' ] [ 'hello' ] ) . to eq ( 'world' )
expect ( json [ 0 ] [ 'user_custom_fields' ] [ 'hidden' ] ) . to be_blank
2018-05-22 17:39:05 -04:00
end
end
2022-03-08 15:08:15 -05:00
describe '#reply_ids' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/ #{ post . id } /reply-ids.json " }
end
it " returns ids of post's replies " do
post = Fabricate ( :post )
reply1 = Fabricate ( :post , topic : post . topic , reply_to_post_number : post . post_number )
reply2 = Fabricate ( :post , topic : post . topic , reply_to_post_number : post . post_number )
PostReply . create ( post_id : post . id , reply_post_id : reply1 . id )
PostReply . create ( post_id : post . id , reply_post_id : reply2 . id )
get " /posts/ #{ post . id } /reply-ids.json "
expect ( response . status ) . to eq ( 200 )
expect ( response . parsed_body ) . to eq ( [
{ " id " = > reply1 . id , " level " = > 1 } ,
{ " id " = > reply2 . id , " level " = > 1 } ,
] )
end
end
2018-05-22 17:39:05 -04:00
describe '#replies' do
include_examples 'finding and showing post' do
let ( :url ) { " /posts/ #{ post . id } /replies.json " }
end
it 'asks post for replies' do
2018-11-13 12:16:50 -05:00
parent = Fabricate ( :post )
child = Fabricate ( :post , topic : parent . topic , reply_to_post_number : parent . post_number )
PostReply . create! ( post : parent , reply : child )
child . user . upsert_custom_fields ( hello : 'world' , hidden : 'dontshow' )
SiteSetting . public_user_custom_fields = 'hello'
get " /posts/ #{ parent . id } /replies.json "
2018-05-22 17:39:05 -04:00
expect ( response . status ) . to eq ( 200 )
2018-11-13 12:16:50 -05:00
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-11-13 12:16:50 -05:00
expect ( json [ 0 ] [ 'id' ] ) . to eq ( child . id )
expect ( json [ 0 ] [ 'user_custom_fields' ] [ 'hello' ] ) . to eq ( 'world' )
expect ( json [ 0 ] [ 'user_custom_fields' ] [ 'hidden' ] ) . to be_blank
2018-05-22 17:39:05 -04:00
end
end
describe '#destroy' do
include_examples 'action requires login' , :delete , " /posts/123.json "
describe 'when logged in' do
let ( :topic ) { Fabricate ( :topic ) }
it " raises an error when the user doesn't have permission to see the post " do
pm = Fabricate ( :private_message_topic )
post = Fabricate ( :post , topic : pm , post_number : 3 )
sign_in ( user )
delete " /posts/ #{ post . id } .json "
expect ( response ) . to be_forbidden
end
2021-01-08 10:05:13 -05:00
it " raises an error when the self deletions are disabled " do
SiteSetting . max_post_deletions_per_day = 0
post = Fabricate ( :post , user : user , topic : topic , post_number : 3 )
sign_in ( user )
delete " /posts/ #{ post . id } .json "
expect ( response ) . to be_forbidden
end
2018-05-22 17:39:05 -04:00
it " uses a PostDestroyer " do
post = Fabricate ( :post , topic_id : topic . id , post_number : 3 )
sign_in ( moderator )
destroyer = mock
PostDestroyer . expects ( :new ) . returns ( destroyer )
destroyer . expects ( :destroy )
delete " /posts/ #{ post . id } .json "
end
2021-10-13 05:53:23 -04:00
context " permanently destroy " do
let! ( :post ) { Fabricate ( :post , topic_id : topic . id , post_number : 3 ) }
before do
SiteSetting . can_permanently_delete = true
end
it " does not work for a post that was not deleted yet " do
sign_in ( admin )
delete " /posts/ #{ post . id } .json " , params : { force_destroy : true }
expect ( response . status ) . to eq ( 403 )
end
it " needs some time to pass to permanently delete a topic " do
sign_in ( admin )
delete " /posts/ #{ post . id } .json "
expect ( response . status ) . to eq ( 200 )
expect ( post . reload . deleted_by_id ) . to eq ( admin . id )
delete " /posts/ #{ post . id } .json " , params : { force_destroy : true }
expect ( response . status ) . to eq ( 403 )
post . update! ( deleted_at : 10 . minutes . ago )
delete " /posts/ #{ post . id } .json " , params : { force_destroy : true }
expect ( response . status ) . to eq ( 200 )
expect { post . reload } . to raise_error ( ActiveRecord :: RecordNotFound )
end
it " needs two users to permanently delete a topic " do
sign_in ( admin )
delete " /posts/ #{ post . id } .json "
expect ( response . status ) . to eq ( 200 )
expect ( post . reload . deleted_by_id ) . to eq ( admin . id )
sign_in ( Fabricate ( :admin ) )
delete " /posts/ #{ post . id } .json " , params : { force_destroy : true }
expect ( response . status ) . to eq ( 200 )
expect { post . reload } . to raise_error ( ActiveRecord :: RecordNotFound )
end
it " moderators cannot permanently delete topics " do
sign_in ( admin )
delete " /posts/ #{ post . id } .json "
expect ( response . status ) . to eq ( 200 )
expect ( post . reload . deleted_by_id ) . to eq ( admin . id )
sign_in ( moderator )
delete " /posts/ #{ post . id } .json " , params : { force_destroy : true }
expect ( response . status ) . to eq ( 403 )
end
end
2018-05-22 17:39:05 -04:00
end
end
describe '#destroy_many' do
include_examples 'action requires login' , :delete , " /posts/destroy_many.json " , params : { post_ids : [ 123 , 345 ] }
describe 'when logged in' do
2019-05-06 23:12:20 -04:00
fab! ( :poster ) { Fabricate ( :moderator ) }
fab! ( :post1 ) { Fabricate ( :post , user : poster , post_number : 2 ) }
fab! ( :post2 ) { Fabricate ( :post , topic : post1 . topic , user : poster , post_number : 3 , reply_to_post_number : post1 . post_number ) }
2018-05-22 17:39:05 -04:00
it " raises invalid parameters no post_ids " do
sign_in ( poster )
delete " /posts/destroy_many.json "
expect ( response . status ) . to eq ( 400 )
expect ( response . message . downcase ) . to eq ( " bad request " )
end
it " raises invalid parameters with missing ids " do
sign_in ( poster )
delete " /posts/destroy_many.json " , params : { post_ids : [ 12345 ] }
expect ( response . status ) . to eq ( 400 )
end
it " raises an error when the user doesn't have permission to delete the posts " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id , post2 . id ] }
expect ( response ) . to be_forbidden
end
it " deletes the post " do
sign_in ( poster )
PostDestroyer . any_instance . expects ( :destroy ) . twice
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id , post2 . id ] }
expect ( response . status ) . to eq ( 200 )
end
it " updates the highest read data for the forum " do
sign_in ( poster )
Topic . expects ( :reset_highest ) . twice
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id , post2 . id ] }
end
describe " can delete replies " do
before do
2020-01-17 11:24:49 -05:00
PostReply . create ( post_id : post1 . id , reply_post_id : post2 . id )
2018-05-22 17:39:05 -04:00
end
it " deletes the post and the reply to it " do
sign_in ( poster )
PostDestroyer . any_instance . expects ( :destroy ) . twice
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id ] , reply_post_ids : [ post1 . id ] }
end
end
2018-11-29 12:14:18 -05:00
context " deleting flagged posts " do
before do
2019-03-06 04:02:25 -05:00
sign_in ( moderator )
2019-01-03 12:03:01 -05:00
PostActionCreator . off_topic ( moderator , post1 )
PostActionCreator . off_topic ( moderator , post2 )
2018-11-29 12:14:18 -05:00
Jobs :: SendSystemMessage . clear
end
2019-03-06 04:02:25 -05:00
it " defers the child posts by default " do
2019-01-03 12:03:01 -05:00
expect ( ReviewableFlaggedPost . pending . count ) . to eq ( 2 )
2019-03-06 04:02:25 -05:00
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id , post2 . id ] }
expect ( Jobs :: SendSystemMessage . jobs . size ) . to eq ( 1 )
2019-01-03 12:03:01 -05:00
expect ( ReviewableFlaggedPost . pending . count ) . to eq ( 0 )
2019-03-06 04:02:25 -05:00
end
it " can defer all posts based on `agree_with_first_reply_flag` param " do
2019-01-03 12:03:01 -05:00
expect ( ReviewableFlaggedPost . pending . count ) . to eq ( 2 )
2019-03-06 04:02:25 -05:00
delete " /posts/destroy_many.json " , params : { post_ids : [ post1 . id , post2 . id ] , agree_with_first_reply_flag : false }
2019-01-03 12:03:01 -05:00
PostActionCreator . off_topic ( moderator , post1 )
PostActionCreator . off_topic ( moderator , post2 )
Jobs :: SendSystemMessage . clear
2018-11-29 12:14:18 -05:00
end
end
2018-05-22 17:39:05 -04:00
end
end
describe '#recover' do
include_examples 'action requires login' , :put , " /posts/123/recover.json "
describe 'when logged in' do
it " raises an error when the user doesn't have permission to see the post " do
post = Fabricate ( :post , topic : Fabricate ( :private_message_topic ) , post_number : 3 )
sign_in ( user )
put " /posts/ #{ post . id } /recover.json "
expect ( response ) . to be_forbidden
end
2021-01-08 10:05:13 -05:00
it " raises an error when self deletion/recovery is disabled " do
SiteSetting . max_post_deletions_per_day = 0
post = Fabricate ( :post , user : user , topic : topic , post_number : 3 )
sign_in ( user )
put " /posts/ #{ post . id } /recover.json "
expect ( response ) . to be_forbidden
end
2018-05-22 17:39:05 -04:00
it " recovers a post correctly " do
topic_id = create_post . topic_id
post = create_post ( topic_id : topic_id )
sign_in ( user )
PostDestroyer . new ( user , post ) . destroy
put " /posts/ #{ post . id } /recover.json "
post . reload
expect ( post . trashed? ) . to be_falsey
end
end
end
describe '#update' do
include_examples 'action requires login' , :put , " /posts/2.json "
2019-05-08 05:56:02 -04:00
let! ( :post ) { post_by_user }
2018-05-22 17:39:05 -04:00
let ( :update_params ) do
{
post : { raw : 'edited body' , edit_reason : 'typo' } ,
image_sizes : { 'http://image.com/image.jpg' = > { 'width' = > 123 , 'height' = > 456 } } ,
}
end
describe 'when logged in as a regular user' do
before do
sign_in ( user )
end
2019-09-06 07:44:12 -04:00
it 'does not allow TL0 or TL1 to update when edit time limit expired' do
2018-05-22 17:39:05 -04:00
SiteSetting . post_edit_time_limit = 5
2019-09-06 07:44:12 -04:00
SiteSetting . tl2_post_edit_time_limit = 30
post = Fabricate ( :post , created_at : 10 . minutes . ago , user : user )
user . update_columns ( trust_level : 1 )
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'errors' ] ) . to include ( I18n . t ( 'too_late_to_edit' ) )
2019-09-06 07:44:12 -04:00
end
it 'does not allow TL2 to update when edit time limit expired' do
SiteSetting . post_edit_time_limit = 12
SiteSetting . tl2_post_edit_time_limit = 8
user . update_columns ( trust_level : 2 )
2018-05-22 17:39:05 -04:00
post = Fabricate ( :post , created_at : 10 . minutes . ago , user : user )
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'errors' ] ) . to include ( I18n . t ( 'too_late_to_edit' ) )
2018-05-22 17:39:05 -04:00
end
it 'passes the image sizes through' do
Post . any_instance . expects ( :image_sizes = )
put " /posts/ #{ post . id } .json " , params : update_params
end
it 'passes the edit reason through' do
put " /posts/ #{ post . id } .json " , params : update_params
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
post . reload
expect ( post . edit_reason ) . to eq ( " typo " )
expect ( post . raw ) . to eq ( " edited body " )
end
2018-10-17 09:35:32 -04:00
it 'checks for an edit conflict' do
update_params [ :post ] [ :raw_old ] = 'old body'
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 409 )
end
2018-05-22 17:39:05 -04:00
it " raises an error when the post parameter is missing " do
update_params . delete ( :post )
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 400 )
expect ( response . message . downcase ) . to eq ( " bad request " )
end
it " raises an error when the user doesn't have permission to see the post " do
post = Fabricate ( :private_message_post , post_number : 3 )
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response ) . to be_forbidden
end
2021-03-24 12:20:38 -04:00
it " updates post's raw attribute " do
2021-06-17 04:53:29 -04:00
put " /posts/ #{ post . id } .json " , params : { post : { raw : 'edited body ' } }
2021-03-24 12:20:38 -04:00
expect ( response . status ) . to eq ( 200 )
2021-06-17 04:53:29 -04:00
expect ( response . parsed_body [ 'post' ] [ 'raw' ] ) . to eq ( 'edited body' )
expect ( post . reload . raw ) . to eq ( 'edited body' )
2018-05-22 17:39:05 -04:00
end
it " extracts links from the new body " do
param = update_params
param [ :post ] [ :raw ] = 'I just visited this https://google.com so many cool links'
put " /posts/ #{ post . id } .json " , params : param
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( TopicLink . count ) . to eq ( 1 )
end
it " doesn't allow updating of deleted posts " do
first_post = post . topic . ordered_posts . first
PostDestroyer . new ( moderator , first_post ) . destroy
put " /posts/ #{ first_post . id } .json " , params : update_params
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-05-22 17:39:05 -04:00
end
end
describe " when logged in as staff " do
before do
sign_in ( moderator )
end
it " supports updating posts in deleted topics " do
first_post = post . topic . ordered_posts . first
PostDestroyer . new ( moderator , first_post ) . destroy
put " /posts/ #{ first_post . id } .json " , params : update_params
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
post . reload
expect ( post . raw ) . to eq ( 'edited body' )
end
2019-03-05 12:02:20 -05:00
it " won't update bump date if post is a whisper " do
2020-03-10 17:13:17 -04:00
created_at = freeze_time 1 . day . ago
2019-03-05 12:02:20 -05:00
post = Fabricate ( :post , post_type : Post . types [ :whisper ] , user : user )
2020-03-10 17:13:17 -04:00
unfreeze_time
2019-03-05 12:02:20 -05:00
put " /posts/ #{ post . id } .json " , params : update_params
2020-03-10 17:13:17 -04:00
expect ( response . status ) . to eq ( 200 )
expect ( post . topic . reload . bumped_at ) . to eq_time ( created_at )
2019-03-05 12:02:20 -05:00
end
2018-05-22 17:39:05 -04:00
end
2020-07-23 09:50:00 -04:00
describe " when logged in as group moderator " do
fab! ( :topic ) { Fabricate ( :topic , category : category ) }
fab! ( :post ) { Fabricate ( :post , user : user , topic : topic ) }
fab! ( :group_user ) { Fabricate ( :group_user ) }
let ( :user_gm ) { group_user . user }
let ( :group ) { group_user . group }
before do
SiteSetting . enable_category_group_moderation = true
post . topic . category . update! ( reviewable_by_group_id : group . id , topic_id : topic . id )
sign_in ( user_gm )
end
it " allows updating the category description " do
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 200 )
post . reload
expect ( post . raw ) . to eq ( 'edited body' )
expect ( UserHistory . where ( action : UserHistory . actions [ :post_edit ] ) . count ) . to eq ( 1 )
end
it " can not update category descriptions in other categories " do
second_category = Fabricate ( :category )
topic . update! ( category : second_category )
put " /posts/ #{ post . id } .json " , params : update_params
expect ( response . status ) . to eq ( 403 )
end
end
2018-05-22 17:39:05 -04:00
it 'can not change category to a disallowed category' do
post = create_post
sign_in ( post . user )
category = Fabricate ( :category )
category . set_permissions ( staff : :full )
category . save!
put " /posts/ #{ post . id } .json " , params : {
post : { category_id : category . id , raw : " this is a test edit to post " }
}
expect ( response . status ) . not_to eq ( 200 )
expect ( post . topic . category_id ) . not_to eq ( category . id )
end
2018-07-12 22:51:08 -04:00
it 'can not move to a category that requires topic approval' do
post = create_post
sign_in ( post . user )
category = Fabricate ( :category )
category . custom_fields [ Category :: REQUIRE_TOPIC_APPROVAL ] = true
category . save!
put " /posts/ #{ post . id } .json " , params : { post : { category_id : category . id , raw : " this is a test edit to post " } }
expect ( response . status ) . to eq ( 403 )
expect ( post . topic . reload . category_id ) . not_to eq ( category . id )
end
2021-03-24 11:22:16 -04:00
describe " with Post.plugin_permitted_update_params " do
before do
plugin = Plugin :: Instance . new
plugin . add_permitted_post_update_param ( :random_number ) do | post , value |
post . custom_fields [ :random_number ] = value
post . save
end
end
after do
DiscoursePluginRegistry . reset!
end
it " calls blocks passed into `add_permitted_post_update_param` " do
sign_in ( post . user )
put " /posts/ #{ post . id } .json " , params : {
post : {
raw : " this is a random post " ,
raw_old : post . raw ,
random_number : 244
}
}
expect ( response . status ) . to eq ( 200 )
expect ( post . reload . custom_fields [ :random_number ] ) . to eq ( " 244 " )
end
end
2018-05-22 17:39:05 -04:00
end
2020-03-11 20:52:15 -04:00
describe " # destroy_bookmark " do
fab! ( :post ) { Fabricate ( :post ) }
2022-05-22 20:07:15 -04:00
fab! ( :bookmark ) { Fabricate ( :bookmark , user : user , bookmarkable : post ) }
2020-03-11 20:52:15 -04:00
before do
sign_in ( user )
end
it " deletes the bookmark " do
bookmark_id = bookmark . id
delete " /posts/ #{ post . id } /bookmark.json "
expect ( Bookmark . find_by ( id : bookmark_id ) ) . to eq ( nil )
end
context " when the user still has bookmarks in the topic " do
before do
2022-05-22 20:07:15 -04:00
Fabricate ( :bookmark , user : user , bookmarkable : Fabricate ( :post , topic : post . topic ) )
2020-03-11 20:52:15 -04:00
end
2021-05-20 21:43:47 -04:00
it " marks topic_bookmarked as true " do
2020-03-11 20:52:15 -04:00
delete " /posts/ #{ post . id } /bookmark.json "
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'topic_bookmarked' ] ) . to eq ( true )
2020-03-11 20:52:15 -04:00
end
end
end
2018-05-22 17:39:05 -04:00
describe '#wiki' do
include_examples " action requires login " , :put , " /posts/2/wiki.json "
describe " when logged in " do
before do
sign_in ( user )
end
2019-05-08 05:56:02 -04:00
let! ( :post ) { post_by_user }
2018-05-22 17:39:05 -04:00
2022-01-24 02:56:18 -05:00
it " returns 400 when wiki parameter is not present " do
sign_in ( admin )
put " /posts/ #{ post . id } /wiki.json " , params : { }
expect ( response . status ) . to eq ( 400 )
end
2018-05-22 17:39:05 -04:00
it " raises an error if the user doesn't have permission to wiki the post " do
put " /posts/ #{ post . id } /wiki.json " , params : { wiki : 'true' }
expect ( response ) . to be_forbidden
end
it " toggle wiki status should create a new version " do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
another_user = Fabricate ( :user )
another_post = Fabricate ( :post , user : another_user )
expect do
put " /posts/ #{ another_post . id } /wiki.json " , params : { wiki : 'true' }
end . to change { another_post . reload . version } . by ( 1 )
expect do
put " /posts/ #{ another_post . id } /wiki.json " , params : { wiki : 'false' }
end . to change { another_post . reload . version } . by ( - 1 )
sign_in ( Fabricate ( :admin ) )
expect do
put " /posts/ #{ another_post . id } /wiki.json " , params : { wiki : 'true' }
end . to change { another_post . reload . version } . by ( 1 )
end
it " can wiki a post " do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ post . id } /wiki.json " , params : { wiki : 'true' }
post . reload
expect ( post . wiki ) . to eq ( true )
end
it " can unwiki a post " do
wikied_post = Fabricate ( :post , user : user , wiki : true )
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ wikied_post . id } /wiki.json " , params : { wiki : 'false' }
wikied_post . reload
expect ( wikied_post . wiki ) . to eq ( false )
end
end
end
describe '#post_type' do
include_examples " action requires login " , :put , " /posts/2/post_type.json "
describe " when logged in " do
before do
2022-01-24 02:56:18 -05:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
end
2019-05-08 05:56:02 -04:00
let! ( :post ) { post_by_user }
2018-05-22 17:39:05 -04:00
it " raises an error if the user doesn't have permission to change the post type " do
2022-01-24 02:56:18 -05:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ post . id } /post_type.json " , params : { post_type : 2 }
expect ( response ) . to be_forbidden
end
2022-01-24 02:56:18 -05:00
it " returns 400 if post_type parameter is not present " do
put " /posts/ #{ post . id } /post_type.json " , params : { }
expect ( response . status ) . to eq ( 400 )
end
it " returns 400 if post_type parameters is invalid " do
put " /posts/ #{ post . id } /post_type.json " , params : { post_type : - 1 }
expect ( response . status ) . to eq ( 400 )
end
2018-05-22 17:39:05 -04:00
it " can change the post type " do
put " /posts/ #{ post . id } /post_type.json " , params : { post_type : 2 }
post . reload
expect ( post . post_type ) . to eq ( 2 )
end
end
end
describe '#rebake' do
include_examples " action requires login " , :put , " /posts/2/rebake.json "
describe " when logged in " do
2019-05-08 05:56:02 -04:00
let! ( :post ) { post_by_user }
2018-05-22 17:39:05 -04:00
it " raises an error if the user doesn't have permission to rebake the post " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ post . id } /rebake.json "
expect ( response ) . to be_forbidden
end
it " can rebake the post " do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ post . id } /rebake.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
2018-12-26 12:52:07 -05:00
it " will invalidate broken images cache " do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2022-05-03 08:53:32 -04:00
PostHotlinkedMedia . create! ( url : " https://example.com/image.jpg " , post : post , status : 'download_failed' )
2018-12-26 12:52:07 -05:00
put " /posts/ #{ post . id } /rebake.json "
post . reload
2022-05-03 08:53:32 -04:00
expect ( post . post_hotlinked_media ) . to eq ( [ ] )
2018-12-26 12:52:07 -05:00
end
2018-05-22 17:39:05 -04:00
end
end
describe '#create' do
include_examples 'action requires login' , :post , " /posts.json "
before do
SiteSetting . min_first_post_typing_time = 0
2019-05-07 13:34:15 -04:00
SiteSetting . enable_whispers = true
2018-05-22 17:39:05 -04:00
end
context 'api' do
it 'memoizes duplicate requests' do
raw = " this is a test post 123 #{ SecureRandom . hash } "
title = " this is a title #{ SecureRandom . hash } "
2019-11-05 09:10:23 -05:00
master_key = Fabricate ( :api_key ) . key
2018-05-22 17:39:05 -04:00
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : raw , title : title , wpid : 1 } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
2018-05-22 17:39:05 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
original = response . body
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : raw , title : title , wpid : 2 } ,
headers : { HTTP_API_USERNAME : user . username_lower , HTTP_API_KEY : master_key }
2018-05-22 17:39:05 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( response . body ) . to eq ( original )
end
it 'allows to create posts in import_mode' do
2019-03-14 10:47:38 -04:00
Jobs . run_immediately!
2018-05-22 17:39:05 -04:00
NotificationEmailer . enable
post_1 = Fabricate ( :post )
2019-11-05 09:10:23 -05:00
master_key = Fabricate ( :api_key ) . key
2018-05-22 17:39:05 -04:00
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : 'this is test reply 1' , topic_id : post_1 . topic . id , reply_to_post_number : 1 } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
2018-05-22 17:39:05 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( post_1 . topic . user . notifications . count ) . to eq ( 1 )
post_1 . topic . user . notifications . destroy_all
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : 'this is test reply 2' , topic_id : post_1 . topic . id , reply_to_post_number : 1 , import_mode : true } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
2018-05-22 17:39:05 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( post_1 . topic . user . notifications . count ) . to eq ( 0 )
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : 'this is test reply 3' , topic_id : post_1 . topic . id , reply_to_post_number : 1 , import_mode : false } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
2018-05-22 17:39:05 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( post_1 . topic . user . notifications . count ) . to eq ( 1 )
end
2019-05-07 13:34:15 -04:00
2022-02-08 22:55:32 -05:00
it 'allows a topic to be created with an external_id' do
master_key = Fabricate ( :api_key ) . key
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : " this is some post " ,
external_id : 'external_id'
} , headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
expect ( response . status ) . to eq ( 200 )
new_topic = Topic . last
expect ( new_topic . external_id ) . to eq ( 'external_id' )
end
2019-05-07 13:34:15 -04:00
it 'prevents whispers for regular users' do
post_1 = Fabricate ( :post )
2019-11-29 10:16:06 -05:00
user_key = ApiKey . create! ( user : user ) . key
2019-05-07 13:34:15 -04:00
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { raw : 'this is test whisper' , topic_id : post_1 . topic . id , reply_to_post_number : 1 , whisper : true } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : user_key }
2019-05-07 13:34:15 -04:00
expect ( response . status ) . to eq ( 403 )
end
2019-05-09 13:22:09 -04:00
2022-02-09 03:37:38 -05:00
it 'does not advance draft' do
Draft . set ( user , Draft :: NEW_TOPIC , 0 , " test " )
user_key = ApiKey . create! ( user : user ) . key
post " /posts.json " ,
params : { title : 'this is a test topic' , raw : 'this is test whisper' } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : user_key }
expect ( response . status ) . to eq ( 200 )
expect ( Draft . get ( user , Draft :: NEW_TOPIC , 0 ) ) . to eq ( " test " )
end
2019-05-09 13:22:09 -04:00
it 'will raise an error if specified category cannot be found' do
user = Fabricate ( :admin )
2019-11-05 09:10:23 -05:00
master_key = Fabricate ( :api_key ) . key
2019-05-09 13:22:09 -04:00
2020-04-06 18:55:44 -04:00
post " /posts.json " ,
params : { title : 'this is a test title' , raw : 'this is test body' , category : 'invalid' } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
2019-05-09 13:22:09 -04:00
2019-05-09 19:33:02 -04:00
expect ( response . status ) . to eq ( 400 )
2019-05-09 13:22:09 -04:00
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ " errors " ] ) . to include (
2019-05-09 19:33:02 -04:00
I18n . t ( " invalid_params " , message : " category " )
)
2019-05-09 13:22:09 -04:00
end
2020-05-23 00:56:13 -04:00
it 'will raise an error if specified embed_url is invalid' do
user = Fabricate ( :admin )
master_key = Fabricate ( :api_key ) . key
post " /posts.json " ,
params : { title : 'this is a test title' , raw : 'this is test body' , embed_url : '/test.txt' } ,
headers : { HTTP_API_USERNAME : user . username , HTTP_API_KEY : master_key }
expect ( response . status ) . to eq ( 422 )
end
2018-05-22 17:39:05 -04:00
end
describe " when logged in " do
2022-02-06 22:23:34 -05:00
fab! ( :user ) { Fabricate ( :user ) }
2018-05-22 17:39:05 -04:00
before do
sign_in ( user )
end
context " fast typing " do
before do
SiteSetting . min_first_post_typing_time = 3000
SiteSetting . auto_silence_fast_typers_max_trust_level = 1
end
it 'queues the post if min_first_post_typing_time is not met' do
post " /posts.json " , params : {
raw : 'this is the test content' ,
2019-06-05 12:12:13 -04:00
title : 'this is the test title for the topic' ,
composer_open_duration_msecs : 204 ,
typing_duration_msecs : 100 ,
reply_to_post_number : 123
2018-05-22 17:39:05 -04:00
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( parsed [ " action " ] ) . to eq ( " enqueued " )
user . reload
expect ( user ) . to be_silenced
2019-04-10 17:42:49 -04:00
rp = ReviewableQueuedPost . find_by ( created_by : user )
2019-06-05 12:12:13 -04:00
expect ( rp . payload [ 'typing_duration_msecs' ] ) . to eq ( 100 )
expect ( rp . payload [ 'composer_open_duration_msecs' ] ) . to eq ( 204 )
expect ( rp . payload [ 'reply_to_post_number' ] ) . to eq ( 123 )
2019-04-11 11:11:35 -04:00
expect ( rp . reviewable_scores . first . reason ) . to eq ( 'fast_typer' )
2018-05-22 17:39:05 -04:00
2019-04-12 09:55:27 -04:00
expect ( parsed [ 'pending_post' ] ) . to be_present
expect ( parsed [ 'pending_post' ] [ 'id' ] ) . to eq ( rp . id )
expect ( parsed [ 'pending_post' ] [ 'raw' ] ) . to eq ( " this is the test content " )
2019-05-06 06:37:30 -04:00
mod = moderator
2019-04-23 12:18:39 -04:00
rp . perform ( mod , :approve_post )
2018-05-22 17:39:05 -04:00
user . reload
expect ( user ) . not_to be_silenced
end
2019-10-02 15:51:40 -04:00
it " doesn't enqueue posts when user first creates a topic " do
2022-02-10 20:00:58 -05:00
topic = Fabricate ( :post , user : user ) . topic
2019-10-02 15:51:40 -04:00
2019-11-26 02:23:10 -05:00
Draft . set ( user , " should_clear " , 0 , " {'a' : 'b'} " )
2019-10-02 15:51:40 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
composer_open_duration_msecs : 204 ,
typing_duration_msecs : 100 ,
2019-11-26 02:23:10 -05:00
topic_id : topic . id ,
draft_key : " should_clear "
2019-10-02 15:51:40 -04:00
}
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2019-10-02 15:51:40 -04:00
expect ( parsed [ " action " ] ) . not_to be_present
2019-11-26 02:23:10 -05:00
expect {
Draft . get ( user , " should_clear " , 0 )
} . to raise_error ( Draft :: OutOfSequence )
2019-10-02 15:51:40 -04:00
end
2018-05-22 17:39:05 -04:00
it " doesn't enqueue replies when the topic is closed " do
topic = Fabricate ( :closed_topic )
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
topic_id : topic . id
}
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( parsed [ " action " ] ) . not_to eq ( " enqueued " )
end
it " doesn't enqueue replies when the post is too long " do
SiteSetting . max_post_length = 10
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic'
}
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( parsed [ " action " ] ) . not_to eq ( " enqueued " )
end
end
2021-02-26 08:07:04 -05:00
it 'silences correctly based on auto_silence_first_post_regex' do
SiteSetting . auto_silence_first_post_regex = " I love candy|i eat s[1-5] "
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'when I eat s3 sometimes when not looking'
}
expect ( response . status ) . to eq ( 200 )
parsed = response . parsed_body
expect ( parsed [ " action " ] ) . to eq ( " enqueued " )
reviewable = ReviewableQueuedPost . find_by ( created_by : user )
score = reviewable . reviewable_scores . first
expect ( score . reason ) . to eq ( 'auto_silence_regex' )
user . reload
2021-05-27 12:19:58 -04:00
expect ( user ) . to be_silenced
end
it 'silences correctly based on silence watched words' do
SiteSetting . watched_words_regular_expressions = true
WatchedWord . create! ( action : WatchedWord . actions [ :silence ] , word : 'I love candy' )
WatchedWord . create! ( action : WatchedWord . actions [ :silence ] , word : 'i eat s[1-5]' )
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'when I eat s3 sometimes when not looking'
}
expect ( response . status ) . to eq ( 200 )
parsed = response . parsed_body
expect ( parsed [ " action " ] ) . to eq ( " enqueued " )
reviewable = ReviewableQueuedPost . find_by ( created_by : user )
score = reviewable . reviewable_scores . first
expect ( score . reason ) . to eq ( 'auto_silence_regex' )
user . reload
2021-02-26 08:07:04 -05:00
expect ( user ) . to be_silenced
end
2018-05-22 17:39:05 -04:00
it " can send a message to a group " do
group = Group . create ( name : 'test_group' , messageable_level : Group :: ALIAS_LEVELS [ :nobody ] )
2019-05-06 11:18:34 -04:00
user1 = user
2018-05-22 17:39:05 -04:00
group . add ( user1 )
2018-03-01 20:13:04 -05:00
2018-05-22 17:39:05 -04:00
post " /posts.json " , params : {
raw : 'I can haz a test' ,
title : 'I loves my test' ,
2020-01-23 10:37:48 -05:00
target_recipients : group . name ,
2018-05-22 17:39:05 -04:00
archetype : Archetype . private_message
}
2018-03-01 20:13:04 -05:00
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-03-01 20:13:04 -05:00
2018-05-22 17:39:05 -04:00
# allow pm to this group
group . update_columns ( messageable_level : Group :: ALIAS_LEVELS [ :everyone ] )
2018-03-01 20:13:04 -05:00
2018-05-22 17:39:05 -04:00
post " /posts.json " , params : {
raw : 'I can haz a test' ,
title : 'I loves my test' ,
2020-05-25 12:04:05 -04:00
target_recipients : " test_Group " ,
2018-05-22 17:39:05 -04:00
archetype : Archetype . private_message
}
2018-03-01 20:13:04 -05:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
post = Post . find ( parsed [ 'id' ] )
2018-03-01 20:13:04 -05:00
2018-05-22 17:39:05 -04:00
expect ( post . topic . topic_allowed_users . length ) . to eq ( 1 )
expect ( post . topic . topic_allowed_groups . length ) . to eq ( 1 )
end
2018-03-01 20:13:04 -05:00
2020-05-27 16:49:00 -04:00
it " can send a message to a group with caps " do
group = Group . create ( name : 'Test_group' , messageable_level : Group :: ALIAS_LEVELS [ :nobody ] )
user1 = user
group . add ( user1 )
# allow pm to this group
group . update_columns ( messageable_level : Group :: ALIAS_LEVELS [ :everyone ] )
post " /posts.json " , params : {
raw : 'I can haz a test' ,
title : 'I loves my test' ,
target_recipients : " test_Group " ,
archetype : Archetype . private_message
}
expect ( response . status ) . to eq ( 200 )
parsed = response . parsed_body
post = Post . find ( parsed [ 'id' ] )
expect ( post . topic . topic_allowed_users . length ) . to eq ( 1 )
expect ( post . topic . topic_allowed_groups . length ) . to eq ( 1 )
end
2018-05-22 17:39:05 -04:00
it " returns the nested post with a param " do
post " /posts.json " , params : {
2021-06-18 09:26:57 -04:00
raw : 'this is the test content ' ,
2018-05-22 17:39:05 -04:00
title : 'this is the test title for the topic' ,
nested_post : true
}
2018-03-01 20:13:04 -05:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
parsed = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( parsed [ 'post' ] ) . to be_present
2021-06-18 09:26:57 -04:00
expect ( parsed [ 'post' ] [ 'raw' ] ) . to eq ( 'this is the test content' )
2018-05-22 17:39:05 -04:00
expect ( parsed [ 'post' ] [ 'cooked' ] ) . to be_present
end
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
it 'protects against dupes' do
raw = " this is a test post 123 #{ SecureRandom . hash } "
title = " this is a title #{ SecureRandom . hash } "
2017-08-31 00:06:56 -04:00
2018-11-13 03:48:04 -05:00
expect do
post " /posts.json " , params : { raw : raw , title : title , wpid : 1 }
end . to change { Post . count }
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
2018-11-13 03:48:04 -05:00
expect do
post " /posts.json " , params : { raw : raw , title : title , wpid : 2 }
end . to_not change { Post . count }
expect ( response . status ) . to eq ( 422 )
2018-05-22 17:39:05 -04:00
end
2017-08-31 00:06:56 -04:00
2020-08-10 18:14:15 -04:00
it 'cannot create a post in a disallowed category' do
2018-05-22 17:39:05 -04:00
category . set_permissions ( staff : :full )
category . save!
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
category : category . id ,
meta_data : { xyz : 'abc' }
}
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
expect ( response . status ) . to eq ( 403 )
end
2017-08-31 00:06:56 -04:00
2020-08-10 18:14:15 -04:00
it 'cannot create a post with a tag that is restricted' do
2019-07-25 12:46:16 -04:00
SiteSetting . tagging_enabled = true
tag = Fabricate ( :tag )
category . allowed_tags = [ tag . name ]
category . save!
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
tags : [ tag . name ] ,
}
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2019-07-25 12:46:16 -04:00
expect ( json [ 'errors' ] ) . to be_present
end
2020-08-10 18:14:15 -04:00
it 'cannot create a post with a tag when tagging is disabled' do
SiteSetting . tagging_enabled = false
tag = Fabricate ( :tag )
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
tags : [ tag . name ] ,
}
expect ( response . status ) . to eq ( 422 )
json = response . parsed_body
expect ( json [ 'errors' ] ) . to be_present
end
it 'cannot create a post with a tag without tagging permission' do
SiteSetting . tagging_enabled = true
SiteSetting . min_trust_level_to_tag_topics = 4
tag = Fabricate ( :tag )
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
tags : [ tag . name ] ,
}
expect ( response . status ) . to eq ( 422 )
json = response . parsed_body
expect ( json [ 'errors' ] ) . to be_present
end
it 'can create a post with a tag when tagging is enabled' do
SiteSetting . tagging_enabled = true
tag = Fabricate ( :tag )
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
tags : [ tag . name ] ,
}
expect ( response . status ) . to eq ( 200 )
expect ( Post . last . topic . tags . count ) . to eq ( 1 )
end
2018-05-22 17:39:05 -04:00
it 'creates the post' do
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
category : category . id ,
meta_data : { xyz : 'abc' }
}
2017-08-31 00:06:56 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
new_post = Post . last
topic = new_post . topic
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
expect ( new_post . user ) . to eq ( user )
expect ( new_post . raw ) . to eq ( 'this is the test content' )
expect ( topic . title ) . to eq ( 'This is the test title for the topic' )
expect ( topic . category ) . to eq ( category )
expect ( topic . meta_data ) . to eq ( " xyz " = > 'abc' )
end
2017-08-31 00:06:56 -04:00
2019-05-09 02:46:43 -04:00
it 'can create an uncategorized topic' do
title = 'this is the test title for the topic'
expect do
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : title ,
category : " "
}
expect ( response . status ) . to eq ( 200 )
end . to change { Topic . count } . by ( 1 )
topic = Topic . last
expect ( topic . title ) . to eq ( title . capitalize )
expect ( topic . category_id ) . to eq ( SiteSetting . uncategorized_category_id )
end
2018-05-22 17:39:05 -04:00
it 'can create a reply to a post' do
topic = Fabricate ( :private_message_post , user : user ) . topic
post_2 = Fabricate ( :private_message_post , user : user , topic : topic )
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
topic_id : topic . id ,
reply_to_post_number : post_2 . post_number ,
image_sizes : { width : '100' , height : '200' }
}
2017-08-31 00:06:56 -04:00
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
new_post = Post . last
topic = new_post . topic
expect ( new_post . user ) . to eq ( user )
expect ( new_post . raw ) . to eq ( 'this is the test content' )
expect ( new_post . reply_to_post_number ) . to eq ( post_2 . post_number )
job_args = Jobs :: ProcessPost . jobs . first [ " args " ] . first
expect ( job_args [ " image_sizes " ] ) . to eq ( " width " = > '100' , " height " = > '200' )
end
it 'creates a private post' do
user_2 = Fabricate ( :user )
2020-05-25 12:04:05 -04:00
user_3 = Fabricate ( :user , username : " foo_bar " )
2018-05-22 17:39:05 -04:00
2020-10-07 20:28:07 -04:00
# In certain edge cases, it's possible to end up with a username
# containing characters that would normally fail to validate
user_4 = Fabricate ( :user , username : " Iyi_Iyi " )
user_4 . update_attribute ( :username , " İyi_İyi " )
user_4 . update_attribute ( :username_lower , " İyi_İyi " . downcase )
2018-05-22 17:39:05 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
2020-10-07 20:28:07 -04:00
target_recipients : " #{ user_2 . username } ,Foo_Bar,İyi_İyi "
2018-05-22 17:39:05 -04:00
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
new_post = Post . last
new_topic = Topic . last
2017-08-31 00:06:56 -04:00
2018-05-22 17:39:05 -04:00
expect ( new_post . user ) . to eq ( user )
expect ( new_topic . private_message? ) . to eq ( true )
2020-10-07 20:28:07 -04:00
expect ( new_topic . allowed_users ) . to contain_exactly ( user , user_2 , user_3 , user_4 )
2018-05-22 17:39:05 -04:00
end
2020-01-20 19:50:44 -05:00
context " when target_recipients not provided " do
it " errors when creating a private post " do
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
target_recipients : " "
}
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ " errors " ] ) . to include (
2020-01-20 19:50:44 -05:00
I18n . t ( " activerecord.errors.models.topic.attributes.base.no_user_selected " )
)
end
end
2020-02-24 09:55:12 -05:00
context " when topic_id is set " do
fab! ( :topic ) { Fabricate ( :topic ) }
it " errors when creating a private post " do
user_2 = Fabricate ( :user )
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
target_recipients : user_2 . username ,
topic_id : topic . id
}
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ " errors " ] ) . to include (
2020-02-24 09:55:12 -05:00
I18n . t ( " create_pm_on_existing_topic " )
)
end
end
2018-05-22 17:39:05 -04:00
context " errors " do
it " does not succeed " do
post " /posts.json " , params : { raw : 'test' }
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-05-22 17:39:05 -04:00
expect ( response . status ) . to eq ( 422 )
end
it " it triggers flag_linked_posts_as_spam when the post creator returns spam " do
SiteSetting . newuser_spam_host_threshold = 1
sign_in ( Fabricate ( :user , trust_level : 0 ) )
post " /posts.json " , params : {
raw : 'this is the test content http://fakespamwebsite.com http://fakespamwebsite.com/spam http://fakespamwebsite.com/spammy' ,
title : 'this is the test title for the topic' ,
meta_data : { xyz : 'abc' }
}
2017-08-31 00:06:56 -04:00
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ " errors " ] ) . to include ( I18n . t ( :spamming_host ) )
2018-05-22 17:39:05 -04:00
end
2019-02-28 09:51:13 -05:00
context " allow_uncategorized_topics is false " do
before do
SiteSetting . allow_uncategorized_topics = false
end
it " cant create an uncategorized post " do
post " /posts.json " , params : {
raw : " a new post with no category " ,
title : " a new post with no category "
}
expect ( response ) . not_to be_successful
end
context " as staff " do
before do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2019-02-28 09:51:13 -05:00
end
it " cant create an uncategorized post " do
post " /posts.json " , params : {
raw : " a new post with no category " ,
title : " a new post with no category "
}
expect ( response ) . not_to be_successful
end
end
end
2018-05-22 17:39:05 -04:00
end
2017-08-31 00:06:56 -04:00
end
2018-03-13 15:59:12 -04:00
describe 'shared draft' do
2019-05-06 23:12:20 -04:00
fab! ( :destination_category ) { Fabricate ( :category ) }
2018-03-13 15:59:12 -04:00
it " will raise an error for regular users " do
post " /posts.json " , params : {
raw : 'this is the shared draft content' ,
title : " this is the shared draft title " ,
category : destination_category . id ,
shared_draft : 'true'
}
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-03-13 15:59:12 -04:00
end
describe " as a staff user " do
before do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-03-13 15:59:12 -04:00
end
it " will raise an error if there is no shared draft category " do
post " /posts.json " , params : {
raw : 'this is the shared draft content' ,
title : " this is the shared draft title " ,
category : destination_category . id ,
shared_draft : 'true'
}
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-03-13 15:59:12 -04:00
end
context " with a shared category " do
2019-05-06 23:12:20 -04:00
fab! ( :shared_category ) { Fabricate ( :category ) }
2018-03-13 15:59:12 -04:00
before do
SiteSetting . shared_drafts_category = shared_category . id
end
it " will work if the shared draft category is present " do
post " /posts.json " , params : {
raw : 'this is the shared draft content' ,
title : " this is the shared draft title " ,
category : destination_category . id ,
shared_draft : 'true'
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
result = response . parsed_body
2018-03-13 15:59:12 -04:00
topic = Topic . find ( result [ 'topic_id' ] )
expect ( topic . category_id ) . to eq ( shared_category . id )
expect ( topic . shared_draft . category_id ) . to eq ( destination_category . id )
end
end
end
end
2017-08-31 00:06:56 -04:00
describe 'warnings' do
2019-05-06 23:12:20 -04:00
fab! ( :user_2 ) { Fabricate ( :user ) }
2017-08-31 00:06:56 -04:00
context 'as a staff user' do
before do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2017-08-31 00:06:56 -04:00
end
it 'should be able to mark a topic as warning' do
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
2020-01-23 10:37:48 -05:00
target_recipients : user_2 . username ,
2017-08-31 00:06:56 -04:00
is_warning : true
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
new_topic = Topic . last
expect ( new_topic . title ) . to eq ( 'This is some post' )
expect ( new_topic . is_official_warning? ) . to eq ( true )
end
it 'should be able to mark a topic as not a warning' do
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
2020-01-23 10:37:48 -05:00
target_recipients : user_2 . username ,
2017-08-31 00:06:56 -04:00
is_warning : false
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
new_topic = Topic . last
expect ( new_topic . title ) . to eq ( 'This is some post' )
expect ( new_topic . is_official_warning? ) . to eq ( false )
end
end
context 'as a normal user' do
it 'should not be able to mark a topic as warning' do
2018-05-22 17:39:05 -04:00
sign_in ( user )
2017-08-31 00:06:56 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
archetype : 'private_message' ,
title : " this is some post " ,
2020-01-23 10:37:48 -05:00
target_recipients : user_2 . username ,
2017-08-31 00:06:56 -04:00
is_warning : true
}
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
new_topic = Topic . last
expect ( new_topic . title ) . to eq ( 'This is some post' )
expect ( new_topic . is_official_warning? ) . to eq ( false )
end
end
end
2018-08-09 20:48:30 -04:00
context " topic bump " do
shared_examples " it works " do
it " should be able to skip topic bumping " do
2020-03-10 17:13:17 -04:00
original_bumped_at = 1 . day . ago
topic = Fabricate ( :topic , bumped_at : original_bumped_at )
2018-08-09 20:48:30 -04:00
post " /posts.json " , params : {
raw : 'this is the test content' ,
topic_id : topic . id ,
no_bump : true
}
expect ( response . status ) . to eq ( 200 )
2020-03-10 17:13:17 -04:00
expect ( topic . reload . bumped_at ) . to eq_time ( original_bumped_at )
2018-08-09 20:48:30 -04:00
end
it " should be able to post with topic bumping " do
post " /posts.json " , params : {
raw : 'this is the test content' ,
topic_id : topic . id
}
expect ( response . status ) . to eq ( 200 )
2020-03-10 17:13:17 -04:00
expect ( topic . reload . bumped_at ) . to eq_time ( topic . posts . last . created_at )
2018-08-09 20:48:30 -04:00
end
end
context " admins " do
before do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-08-09 20:48:30 -04:00
end
include_examples " it works "
end
context " moderators " do
before do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-08-09 20:48:30 -04:00
end
include_examples " it works "
end
2019-01-03 08:13:36 -05:00
context " TL4 users " do
2019-05-06 11:20:48 -04:00
fab! ( :trust_level_4 ) { Fabricate ( :trust_level_4 ) }
2019-01-03 08:13:36 -05:00
before do
2019-05-06 11:20:48 -04:00
sign_in ( trust_level_4 )
2019-01-03 08:13:36 -05:00
end
include_examples " it works "
end
2018-08-09 20:48:30 -04:00
context " users " do
2019-05-06 23:12:20 -04:00
fab! ( :topic ) { Fabricate ( :topic ) }
2018-08-09 20:48:30 -04:00
2019-01-03 08:13:36 -05:00
[ :user ] . each do | user |
2018-08-09 20:48:30 -04:00
it " will raise an error for #{ user } " do
sign_in ( Fabricate ( user ) )
post " /posts.json " , params : {
raw : 'this is the test content' ,
topic_id : topic . id ,
no_bump : true
}
expect ( response . status ) . to eq ( 400 )
end
end
end
end
2021-08-05 05:38:39 -04:00
describe " featured links " do
it " allows to create topics with featured links " do
sign_in ( user_trust_level_1 )
post " /posts.json " , params : {
title : " this is the test title for the topic " ,
raw : " this is the test content " ,
featured_link : " https://discourse.org "
}
expect ( response . status ) . to eq ( 200 )
end
it " doesn't allow TL0 users to create topics with featured links " do
sign_in ( user_trust_level_0 )
post " /posts.json " , params : {
title : " this is the test title for the topic " ,
raw : " this is the test content " ,
featured_link : " https://discourse.org "
}
expect ( response . status ) . to eq ( 422 )
end
it " doesn't allow to create topics with featured links if featured links are disabled in settings " do
SiteSetting . topic_featured_link_enabled = false
sign_in ( user_trust_level_1 )
post " /posts.json " , params : {
title : " this is the test title for the topic " ,
raw : " this is the test content " ,
featured_link : " https://discourse.org "
}
expect ( response . status ) . to eq ( 422 )
end
it " doesn't allow to create topics with featured links in the category with forbidden feature links " do
category = Fabricate ( :category , topic_featured_link_allowed : false )
sign_in ( user_trust_level_1 )
post " /posts.json " , params : {
title : " this is the test title for the topic " ,
raw : " this is the test content " ,
featured_link : " https://discourse.org " ,
category : category . id
}
expect ( response . status ) . to eq ( 422 )
end
end
2017-08-31 00:06:56 -04:00
end
2018-05-22 17:39:05 -04:00
describe '#revisions' do
2019-05-06 23:12:20 -04:00
fab! ( :post ) { Fabricate ( :post , version : 2 ) }
2018-05-22 17:39:05 -04:00
let ( :post_revision ) { Fabricate ( :post_revision , post : post ) }
it " throws an exception when revision is < 2 " do
get " /posts/ #{ post . id } /revisions/1.json "
expect ( response . status ) . to eq ( 400 )
end
context " when edit history is not visible to the public " do
before { SiteSetting . edit_history_visible_to_public = false }
it " ensures anonymous cannot see the revisions " do
get " /posts/ #{ post . id } /revisions/ #{ post_revision . number } .json "
expect ( response ) . to be_forbidden
end
it " ensures regular user cannot see the revisions " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ post . id } /revisions/ #{ post_revision . number } .json "
expect ( response ) . to be_forbidden
end
it " ensures staff can see the revisions " do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ post . id } /revisions/ #{ post_revision . number } .json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
it " ensures poster can see the revisions " do
user = Fabricate ( :active_user )
sign_in ( user )
post = Fabricate ( :post , user : user , version : 3 )
pr = Fabricate ( :post_revision , user : user , post : post )
get " /posts/ #{ pr . post_id } /revisions/ #{ pr . number } .json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
2020-06-18 06:27:51 -04:00
it " ensures trust level 4 cannot see the revisions " do
2018-05-22 17:39:05 -04:00
sign_in ( Fabricate ( :user , trust_level : 4 ) )
get " /posts/ #{ post_revision . post_id } /revisions/ #{ post_revision . number } .json "
2020-06-18 06:27:51 -04:00
expect ( response . status ) . to eq ( 403 )
2018-05-22 17:39:05 -04:00
end
end
2018-10-31 10:47:00 -04:00
context " when post is hidden " do
before {
post . hidden = true
post . save
}
it " throws an exception for users " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-10-31 10:47:00 -04:00
get " /posts/ #{ post . id } /revisions/ #{ post_revision . number } .json "
expect ( response . status ) . to eq ( 404 )
end
it " works for admins " do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-10-31 10:47:00 -04:00
get " /posts/ #{ post . id } /revisions/ #{ post_revision . number } .json "
expect ( response . status ) . to eq ( 200 )
end
end
2018-05-22 17:39:05 -04:00
context " when edit history is visible to everyone " do
before { SiteSetting . edit_history_visible_to_public = true }
it " ensures anyone can see the revisions " do
get " /posts/ #{ post_revision . post_id } /revisions/ #{ post_revision . number } .json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
end
context " deleted post " do
2019-05-06 23:12:20 -04:00
fab! ( :deleted_post ) { Fabricate ( :post , user : admin , version : 3 ) }
fab! ( :deleted_post_revision ) { Fabricate ( :post_revision , user : admin , post : deleted_post ) }
2018-05-22 17:39:05 -04:00
before { deleted_post . trash! ( admin ) }
it " also work on deleted post " do
sign_in ( admin )
get " /posts/ #{ deleted_post_revision . post_id } /revisions/ #{ deleted_post_revision . number } .json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
end
context " deleted topic " do
2019-05-06 23:12:20 -04:00
fab! ( :deleted_topic ) { Fabricate ( :topic , user : admin ) }
fab! ( :post ) { Fabricate ( :post , user : admin , topic : deleted_topic , version : 3 ) }
fab! ( :post_revision ) { Fabricate ( :post_revision , user : admin , post : post ) }
2018-05-22 17:39:05 -04:00
before { deleted_topic . trash! ( admin ) }
it " also work on deleted topic " do
sign_in ( admin )
get " /posts/ #{ post_revision . post_id } /revisions/ #{ post_revision . number } .json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
end
end
describe '#revert' do
include_examples 'action requires login' , :put , " /posts/123/revisions/2/revert.json "
2019-05-06 23:12:20 -04:00
fab! ( :post ) { Fabricate ( :post , user : Fabricate ( :user ) , raw : " Lorem ipsum dolor sit amet, cu nam libris tractatos, ancillae senserit ius ex " ) }
2018-05-22 17:39:05 -04:00
let ( :post_revision ) { Fabricate ( :post_revision , post : post , modifications : { " raw " = > [ " this is original post body. " , " this is edited post body. " ] } ) }
let ( :blank_post_revision ) { Fabricate ( :post_revision , post : post , modifications : { " edit_reason " = > [ " edit reason # 1 " , " edit reason # 2 " ] } ) }
let ( :same_post_revision ) { Fabricate ( :post_revision , post : post , modifications : { " raw " = > [ " Lorem ipsum dolor sit amet, cu nam libris tractatos, ancillae senserit ius ex " , " this is edited post body. " ] } ) }
let ( :post_id ) { post . id }
let ( :revision_id ) { post_revision . number }
describe 'when logged in as a regular user' do
it " does not work " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
put " /posts/ #{ post_id } /revisions/ #{ revision_id } /revert.json "
2018-06-05 03:29:17 -04:00
expect ( response ) . to_not be_successful
2018-05-22 17:39:05 -04:00
end
end
describe " when logged in as staff " do
before do
sign_in ( moderator )
end
it " fails when revision is < 2 " do
put " /posts/ #{ post_id } /revisions/1/revert.json "
expect ( response . status ) . to eq ( 400 )
end
it " fails when post_revision record is not found " do
put " /posts/ #{ post_id } /revisions/ #{ revision_id + 1 } /revert.json "
2018-06-05 03:29:17 -04:00
expect ( response ) . to_not be_successful
2018-05-22 17:39:05 -04:00
end
it " fails when post record is not found " do
put " /posts/ #{ post_id + 1 } /revisions/ #{ revision_id } /revert.json "
2018-06-05 03:29:17 -04:00
expect ( response ) . to_not be_successful
2018-05-22 17:39:05 -04:00
end
it " fails when revision is blank " do
put " /posts/ #{ post_id } /revisions/ #{ blank_post_revision . number } /revert.json "
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'errors' ] ) . to include ( I18n . t ( 'revert_version_same' ) )
2018-05-22 17:39:05 -04:00
end
it " fails when revised version is same as current version " do
put " /posts/ #{ post_id } /revisions/ #{ same_post_revision . number } /revert.json "
expect ( response . status ) . to eq ( 422 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'errors' ] ) . to include ( I18n . t ( 'revert_version_same' ) )
2018-05-22 17:39:05 -04:00
end
it " works! " do
put " /posts/ #{ post_id } /revisions/ #{ revision_id } /revert.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
it " supports reverting posts in deleted topics " do
first_post = post . topic . ordered_posts . first
PostDestroyer . new ( moderator , first_post ) . destroy
put " /posts/ #{ post_id } /revisions/ #{ revision_id } /revert.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
end
end
describe '#expand_embed' do
before do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
end
2019-05-06 23:12:20 -04:00
fab! ( :post ) { Fabricate ( :post ) }
2018-05-22 17:39:05 -04:00
it " raises an error when you can't see the post " do
post = Fabricate ( :private_message_post )
get " /posts/ #{ post . id } /expand-embed.json "
2018-06-05 03:29:17 -04:00
expect ( response ) . not_to be_successful
2018-05-22 17:39:05 -04:00
end
it " retrieves the body when you can see the post " do
TopicEmbed . expects ( :expanded_for ) . with ( post ) . returns ( " full content " )
get " /posts/ #{ post . id } /expand-embed.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
expect ( response . parsed_body [ 'cooked' ] ) . to eq ( " full content " )
2018-05-22 17:39:05 -04:00
end
end
2021-08-18 21:58:26 -04:00
describe '#flagged_posts' do
include_examples " action requires login " , :get , " /posts/system/flagged.json "
describe " when logged in " do
it " raises an error if the user doesn't have permission to see the flagged posts " do
sign_in ( user )
get " /posts/system/flagged.json "
expect ( response ) . to be_forbidden
end
it " can see the flagged posts when authorized " do
sign_in ( moderator )
get " /posts/system/flagged.json "
expect ( response . status ) . to eq ( 200 )
end
it " only shows agreed and deferred flags " do
post_agreed = create_post ( user : user )
post_deferred = create_post ( user : user )
post_disagreed = create_post ( user : user )
r0 = PostActionCreator . spam ( moderator , post_agreed ) . reviewable
r1 = PostActionCreator . off_topic ( moderator , post_deferred ) . reviewable
r2 = PostActionCreator . inappropriate ( moderator , post_disagreed ) . reviewable
r0 . perform ( admin , :agree_and_keep )
r1 . perform ( admin , :ignore )
r2 . perform ( admin , :disagree )
sign_in ( Fabricate ( :moderator ) )
get " /posts/ #{ user . username } /flagged.json "
expect ( response . status ) . to eq ( 200 )
expect ( response . parsed_body . length ) . to eq ( 2 )
end
end
end
2018-05-22 17:39:05 -04:00
describe '#deleted_posts' do
include_examples " action requires login " , :get , " /posts/system/deleted.json "
describe " when logged in " do
it " raises an error if the user doesn't have permission to see the deleted posts " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
get " /posts/system/deleted.json "
expect ( response ) . to be_forbidden
end
it " can see the deleted posts when authorized " do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
get " /posts/system/deleted.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
end
2022-07-05 03:51:21 -04:00
it " does not raise if topic has been permanently deleted " do
post = Fabricate ( :post , user : admin )
PostDestroyer . new ( admin , post ) . destroy
post . update! ( topic_id : - 1000 )
sign_in ( admin )
get " /posts/ #{ admin . username } /deleted.json "
expect ( response . status ) . to eq ( 200 )
end
2018-05-22 17:39:05 -04:00
it " doesn't return secured categories for moderators if they don't have access " do
Fabricate ( :moderator )
group = Fabricate ( :group )
group . add_owner ( user )
secured_category = Fabricate ( :private_category , group : group )
secured_post = create_post ( user : user , category : secured_category )
PostDestroyer . new ( admin , secured_post ) . destroy
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ user . username } /deleted.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
data = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( data . length ) . to eq ( 0 )
end
it " doesn't return PMs for moderators " do
Fabricate ( :moderator )
pm_post = create_post ( user : user , archetype : 'private_message' , target_usernames : [ admin . username ] )
PostDestroyer . new ( admin , pm_post ) . destroy
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ user . username } /deleted.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
data = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( data . length ) . to eq ( 0 )
end
it " only shows posts deleted by other users " do
create_post ( user : user )
post_deleted_by_user = create_post ( user : user )
post_deleted_by_admin = create_post ( user : user )
PostDestroyer . new ( user , post_deleted_by_user ) . destroy
PostDestroyer . new ( admin , post_deleted_by_admin ) . destroy
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ user . username } /deleted.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
data = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( data . length ) . to eq ( 1 )
expect ( data [ 0 ] [ " id " ] ) . to eq ( post_deleted_by_admin . id )
expect ( data [ 0 ] [ " deleted_by " ] [ " id " ] ) . to eq ( admin . id )
end
end
end
describe '#markdown_id' do
it " can be viewed by anonymous " do
post = Fabricate ( :post , raw : " 123456789 " )
get " /posts/ #{ post . id } /raw.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( response . body ) . to eq ( " 123456789 " )
end
2022-03-08 11:42:07 -05:00
it " renders a 404 page " do
get " /posts/0/raw "
expect ( response . status ) . to eq ( 404 )
expect ( response . body ) . to include ( I18n . t ( " page_not_found.title " ) )
end
2018-05-22 17:39:05 -04:00
end
describe '#markdown_num' do
it " can be viewed by anonymous " do
topic = Fabricate ( :topic )
post = Fabricate ( :post , topic : topic , post_number : 1 , raw : " 123456789 " )
post . save
get " /raw/ #{ topic . id } /1.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
expect ( response . body ) . to eq ( " 123456789 " )
end
2022-01-17 16:05:14 -05:00
it " can show whole topics " do
topic = Fabricate ( :topic )
post = Fabricate ( :post , topic : topic , post_number : 1 , raw : " 123456789 " )
post_2 = Fabricate ( :post , topic : topic , post_number : 2 , raw : " abcdefghij " )
post . save
get " /raw/ #{ topic . id } "
expect ( response . status ) . to eq ( 200 )
expect ( response . body ) . to include ( " 123456789 " , " abcdefghij " )
end
2018-05-22 17:39:05 -04:00
end
describe '#short_link' do
2019-05-06 23:12:20 -04:00
fab! ( :topic ) { Fabricate ( :topic ) }
fab! ( :post ) { Fabricate ( :post , topic : topic ) }
2018-05-22 17:39:05 -04:00
it " redirects to the topic " do
get " /p/ #{ post . id } .json "
expect ( response ) . to be_redirect
end
2022-07-27 17:29:13 -04:00
it " returns a 403 when access is denied for JSON format " do
2018-05-22 17:39:05 -04:00
post = Fabricate ( :private_message_post )
get " /p/ #{ post . id } .json "
expect ( response ) . to be_forbidden
end
2022-03-08 11:42:07 -05:00
2022-07-27 17:29:13 -04:00
it " returns a 403 when access is denied for HTML format " do
post = Fabricate ( :private_message_post )
get " /p/ #{ post . id } "
expect ( response ) . to be_forbidden
expect ( response . body ) . to have_tag ( " body.no-ember " )
end
2022-03-08 11:42:07 -05:00
it " renders a 404 page " do
get " /p/0 "
expect ( response . status ) . to eq ( 404 )
expect ( response . body ) . to include ( I18n . t ( " page_not_found.title " ) )
end
2018-05-22 17:39:05 -04:00
end
2017-08-31 00:06:56 -04:00
describe '#user_posts_feed' do
it 'returns public posts rss feed' do
public_post
private_post
get " /u/ #{ user . username } /activity.rss "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
body = response . body
expect ( body ) . to_not include ( private_post . url )
expect ( body ) . to include ( public_post . url )
end
2018-10-09 10:21:41 -04:00
it 'returns public posts as JSON' do
public_post
private_post
get " /u/ #{ user . username } /activity.json "
expect ( response . status ) . to eq ( 200 )
body = response . body
expect ( body ) . to_not include ( private_post . topic . slug )
expect ( body ) . to include ( public_post . topic . slug )
end
2020-06-03 09:33:02 -04:00
it " returns 404 if `hide_profile_and_presence` user option is checked " do
user . user_option . update_columns ( hide_profile_and_presence : true )
get " /u/ #{ user . username } /activity.rss "
expect ( response . status ) . to eq ( 404 )
get " /u/ #{ user . username } /activity.json "
expect ( response . status ) . to eq ( 404 )
end
2020-10-09 17:18:44 -04:00
it " succeeds when `allow_users_to_hide_profile` is false " do
user . user_option . update_columns ( hide_profile_and_presence : true )
SiteSetting . allow_users_to_hide_profile = false
get " /u/ #{ user . username } /activity.rss "
expect ( response . status ) . to eq ( 200 )
get " /u/ #{ user . username } /activity.json "
expect ( response . status ) . to eq ( 200 )
end
2017-08-31 00:06:56 -04:00
end
describe '#latest' do
context 'private posts' do
2019-05-16 22:07:18 -04:00
describe 'when not logged in' do
it 'should return the right response' do
Fabricate ( :post )
get " /private-posts.rss "
expect ( response . status ) . to eq ( 404 )
expect ( response . body ) . to have_tag (
" input " , with : { value : " private_posts " }
)
end
end
2017-08-31 00:06:56 -04:00
it 'returns private posts rss feed' do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2017-08-31 00:06:56 -04:00
public_post
private_post
get " /private-posts.rss "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
body = response . body
expect ( body ) . to include ( private_post . url )
expect ( body ) . to_not include ( public_post . url )
end
2018-05-22 17:39:05 -04:00
it 'returns private posts for json' do
2019-05-06 05:36:54 -04:00
sign_in ( admin )
2018-05-22 17:39:05 -04:00
public_post
private_post
get " /private-posts.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-05-22 17:39:05 -04:00
post_ids = json [ 'private_posts' ] . map { | p | p [ 'id' ] }
expect ( post_ids ) . to include private_post . id
expect ( post_ids ) . to_not include public_post . id
end
2017-08-31 00:06:56 -04:00
end
context 'public posts' do
it 'returns public posts with topic rss feed' do
public_post
private_post
get " /posts.rss "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2017-08-31 00:06:56 -04:00
body = response . body
2022-03-15 05:17:06 -04:00
# we cache in redis, in rare cases this can cause a flaky test
PostsHelper . clear_canonical_cache! ( public_post )
expect ( body ) . to include ( public_post . canonical_url )
2017-08-31 00:06:56 -04:00
expect ( body ) . to_not include ( private_post . url )
end
2018-05-22 17:39:05 -04:00
it 'returns public posts with topic for json' do
topicless_post . update topic_id : - 100
public_post
private_post
topicless_post
get " /posts.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-05-22 17:39:05 -04:00
post_ids = json [ 'latest_posts' ] . map { | p | p [ 'id' ] }
expect ( post_ids ) . to include public_post . id
expect ( post_ids ) . to_not include private_post . id
expect ( post_ids ) . to_not include topicless_post . id
end
end
end
describe '#cooked' do
2021-05-20 21:43:47 -04:00
it 'returns the cooked content' do
2018-05-22 17:39:05 -04:00
post = Fabricate ( :post , cooked : " WAt " )
get " /posts/ #{ post . id } /cooked.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( json ) . to be_present
expect ( json [ 'cooked' ] ) . to eq ( 'WAt' )
end
end
describe '#raw_email' do
include_examples " action requires login " , :get , " /posts/2/raw-email.json "
describe " when logged in " do
let ( :post ) { Fabricate ( :post , deleted_at : 2 . hours . ago , user : Fabricate ( :user ) , raw_email : 'email_content' ) }
it " raises an error if the user doesn't have permission to view raw email " do
2019-05-06 11:18:34 -04:00
sign_in ( user )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ post . id } /raw-email.json "
expect ( response ) . to be_forbidden
end
it " can view raw email " do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-05-22 17:39:05 -04:00
get " /posts/ #{ post . id } /raw-email.json "
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-05-22 17:39:05 -04:00
2020-05-07 11:04:12 -04:00
json = response . parsed_body
2018-05-22 17:39:05 -04:00
expect ( json [ 'raw_email' ] ) . to eq ( 'email_content' )
end
2017-08-31 00:06:56 -04:00
end
end
2018-01-25 15:38:40 -05:00
describe " # locked " do
before do
2019-05-06 06:37:30 -04:00
sign_in ( moderator )
2018-01-25 15:38:40 -05:00
end
it 'can lock and unlock the post' do
put " /posts/ #{ public_post . id } /locked.json " , params : { locked : " true " }
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-01-25 15:38:40 -05:00
public_post . reload
expect ( public_post ) . to be_locked
put " /posts/ #{ public_post . id } /locked.json " , params : { locked : " false " }
2018-06-07 04:11:09 -04:00
expect ( response . status ) . to eq ( 200 )
2018-01-25 15:38:40 -05:00
public_post . reload
expect ( public_post ) . not_to be_locked
end
end
2019-07-09 07:42:02 -04:00
describe " # notice " do
2020-07-20 15:53:47 -04:00
it 'can create and remove notices as a moderator' do
2019-07-09 07:42:02 -04:00
sign_in ( moderator )
2020-11-11 07:49:53 -05:00
raw_notice = " Hello *world*! \n \n https://github.com/discourse/discourse "
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : raw_notice }
2019-07-09 07:42:02 -04:00
expect ( response . status ) . to eq ( 200 )
2020-11-11 07:49:53 -05:00
expect ( public_post . reload . custom_fields [ Post :: NOTICE ] ) . to eq ( " type " = > Post . notices [ :custom ] , " raw " = > raw_notice , " cooked " = > PrettyText . cook ( raw_notice , features : { onebox : false } ) )
2020-07-21 14:29:02 -04:00
expect ( UserHistory . where ( action : UserHistory . actions [ :post_staff_note_create ] ) . count ) . to eq ( 1 )
2019-07-09 07:42:02 -04:00
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : nil }
expect ( response . status ) . to eq ( 200 )
2020-11-11 07:49:53 -05:00
expect ( public_post . reload . custom_fields [ Post :: NOTICE ] ) . to eq ( nil )
2020-07-21 14:29:02 -04:00
expect ( UserHistory . where ( action : UserHistory . actions [ :post_staff_note_destroy ] ) . count ) . to eq ( 1 )
2019-07-09 07:42:02 -04:00
end
2020-07-20 15:53:47 -04:00
describe 'group moderators' do
fab! ( :group_user ) { Fabricate ( :group_user ) }
let ( :user ) { group_user . user }
let ( :group ) { group_user . group }
before do
SiteSetting . enable_category_group_moderation = true
topic . category . update! ( reviewable_by_group_id : group . id )
sign_in ( user )
end
it 'can create and remove notices as a group moderator' do
2020-11-11 07:49:53 -05:00
raw_notice = " Hello *world*! \n \n https://github.com/discourse/discourse "
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : raw_notice }
2020-07-20 15:53:47 -04:00
expect ( response . status ) . to eq ( 200 )
2020-11-11 07:49:53 -05:00
expect ( public_post . reload . custom_fields [ Post :: NOTICE ] ) . to eq ( " type " = > Post . notices [ :custom ] , " raw " = > raw_notice , " cooked " = > PrettyText . cook ( raw_notice , features : { onebox : false } ) )
2020-07-20 15:53:47 -04:00
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : nil }
expect ( response . status ) . to eq ( 200 )
2020-11-11 07:49:53 -05:00
expect ( public_post . reload . custom_fields [ Post :: NOTICE ] ) . to eq ( nil )
2020-07-20 15:53:47 -04:00
end
it 'prevents a group moderator from altering notes outside of their category' do
moderatable_group = Fabricate ( :group )
topic . category . update! ( reviewable_by_group_id : moderatable_group . id )
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : " Hello " }
expect ( response . status ) . to eq ( 404 )
end
it 'prevents a normal user from altering notes' do
group_user . destroy!
put " /posts/ #{ public_post . id } /notice.json " , params : { notice : " Hello " }
expect ( response . status ) . to eq ( 404 )
end
end
2019-07-09 07:42:02 -04:00
end
2019-12-20 11:37:12 -05:00
2021-08-26 12:16:00 -04:00
describe " # pending " do
subject ( :request ) { get " /posts/ #{ user . username } /pending.json " }
context " when user is not logged in " do
it_behaves_like " action requires login " , :get , " /posts/system/pending.json "
end
context " when user is logged in " do
let ( :pending_posts ) { response . parsed_body [ " pending_posts " ] }
before { sign_in ( current_user ) }
context " when current user is the same as user " do
let ( :current_user ) { user }
context " when there are existing pending posts " do
let! ( :owner_pending_posts ) { Fabricate . times ( 2 , :reviewable_queued_post , created_by : user ) }
let! ( :other_pending_post ) { Fabricate ( :reviewable_queued_post ) }
let ( :expected_keys ) do
%w[
avatar_template
category_id
created_at
created_by_id
name
raw_text
title
topic_id
topic_url
username
]
end
it " returns user's pending posts " do
request
expect ( pending_posts ) . to all include " id " = > be_in ( owner_pending_posts . map ( & :id ) )
expect ( pending_posts ) . to all include ( * expected_keys )
end
end
context " when there aren't any pending posts " do
it " returns an empty array " do
request
expect ( pending_posts ) . to be_empty
end
end
end
context " when current user is a staff member " do
let ( :current_user ) { moderator }
context " when there are existing pending posts " do
let! ( :owner_pending_posts ) { Fabricate . times ( 2 , :reviewable_queued_post , created_by : user ) }
let! ( :other_pending_post ) { Fabricate ( :reviewable_queued_post ) }
let ( :expected_keys ) do
%w[
avatar_template
category_id
created_at
created_by_id
name
raw_text
title
topic_id
topic_url
username
]
end
it " returns user's pending posts " do
request
expect ( pending_posts ) . to all include " id " = > be_in ( owner_pending_posts . map ( & :id ) )
expect ( pending_posts ) . to all include ( * expected_keys )
end
end
context " when there aren't any pending posts " do
it " returns an empty array " do
request
expect ( pending_posts ) . to be_empty
end
end
end
context " when current user is another user " do
let ( :current_user ) { Fabricate ( :user ) }
it " does not allow access " do
request
expect ( response ) . to have_http_status :not_found
end
end
end
end
2019-12-20 11:37:12 -05:00
describe Plugin :: Instance do
describe '#add_permitted_post_create_param' do
fab! ( :user ) { Fabricate ( :user ) }
let ( :instance ) { Plugin :: Instance . new }
let ( :request ) do
Proc . new {
post " /posts.json " , params : {
raw : 'this is the test content' ,
title : 'this is the test title for the topic' ,
composer_open_duration_msecs : 204 ,
typing_duration_msecs : 100 ,
reply_to_post_number : 123 ,
string_arg : '123' ,
hash_arg : { key1 : 'val' } ,
array_arg : [ '1' , '2' , '3' ]
}
}
end
before do
sign_in ( user )
SiteSetting . min_first_post_typing_time = 0
end
it 'allows strings to be added' do
request . call
expect ( @controller . send ( :create_params ) ) . not_to include ( string_arg : '123' )
instance . add_permitted_post_create_param ( :string_arg )
request . call
expect ( @controller . send ( :create_params ) ) . to include ( string_arg : '123' )
end
it 'allows hashes to be added' do
instance . add_permitted_post_create_param ( :hash_arg )
request . call
expect ( @controller . send ( :create_params ) ) . not_to include ( hash_arg : { key1 : 'val' } )
instance . add_permitted_post_create_param ( :hash_arg , :hash )
request . call
expect ( @controller . send ( :create_params ) ) . to include ( hash_arg : { key1 : 'val' } )
end
it 'allows strings to be added' do
instance . add_permitted_post_create_param ( :array_arg )
request . call
expect ( @controller . send ( :create_params ) ) . not_to include ( array_arg : [ '1' , '2' , '3' ] )
instance . add_permitted_post_create_param ( :array_arg , :array )
request . call
expect ( @controller . send ( :create_params ) ) . to include ( array_arg : [ '1' , '2' , '3' ] )
end
end
end
2017-08-31 00:06:56 -04:00
end