2019-04-30 08:27:42 +08:00
# frozen_string_literal: true
2017-08-24 11:01:11 +08:00
require 'rails_helper'
RSpec . describe TopicsController do
2019-05-07 11:12:20 +08:00
fab! ( :topic ) { Fabricate ( :topic ) }
fab! ( :user ) { Fabricate ( :user ) }
2019-05-08 17:06:54 +08:00
fab! ( :moderator ) { Fabricate ( :moderator ) }
2019-05-06 18:00:22 +08:00
fab! ( :admin ) { Fabricate ( :admin ) }
2019-05-06 19:19:50 +08:00
fab! ( :trust_level_4 ) { Fabricate ( :trust_level_4 ) }
2017-08-24 11:01:11 +08:00
2018-05-31 22:45:32 +08:00
describe '#wordpress' do
2019-05-08 17:06:54 +08:00
let! ( :user ) { sign_in ( moderator ) }
let ( :p1 ) { Fabricate ( :post , user : moderator ) }
2018-05-31 22:45:32 +08:00
let ( :topic ) { p1 . topic }
2019-05-08 17:06:54 +08:00
let! ( :p2 ) { Fabricate ( :post , topic : topic , user : moderator ) }
2018-05-31 22:45:32 +08:00
it " returns the JSON in the format our wordpress plugin needs " do
SiteSetting . external_system_avatars_enabled = false
get " /t/ #{ topic . id } /wordpress.json " , params : { best : 3 }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
json = :: JSON . parse ( response . body )
# The JSON has the data the wordpress plugin needs
expect ( json [ 'id' ] ) . to eq ( topic . id )
expect ( json [ 'posts_count' ] ) . to eq ( 2 )
expect ( json [ 'filtered_posts_count' ] ) . to eq ( 2 )
# Posts
expect ( json [ 'posts' ] . size ) . to eq ( 1 )
post = json [ 'posts' ] [ 0 ]
expect ( post [ 'id' ] ) . to eq ( p2 . id )
expect ( post [ 'username' ] ) . to eq ( user . username )
expect ( post [ 'avatar_template' ] ) . to eq ( " #{ Discourse . base_url_no_prefix } #{ user . avatar_template } " )
expect ( post [ 'name' ] ) . to eq ( user . name )
expect ( post [ 'created_at' ] ) . to be_present
expect ( post [ 'cooked' ] ) . to eq ( p2 . cooked )
# Participants
expect ( json [ 'participants' ] . size ) . to eq ( 1 )
participant = json [ 'participants' ] [ 0 ]
expect ( participant [ 'id' ] ) . to eq ( user . id )
expect ( participant [ 'username' ] ) . to eq ( user . username )
expect ( participant [ 'avatar_template' ] ) . to eq ( " #{ Discourse . base_url_no_prefix } #{ user . avatar_template } " )
end
end
describe '#move_posts' do
before do
SiteSetting . min_topic_title_length = 2
2018-07-07 00:21:32 +08:00
SiteSetting . tagging_enabled = true
2018-05-31 22:45:32 +08:00
end
it 'needs you to be logged in' do
post " /t/111/move-posts.json " , params : {
title : 'blah' ,
post_ids : [ 1 , 2 , 3 ]
}
expect ( response . status ) . to eq ( 403 )
end
describe 'moving to a new topic' do
let ( :p1 ) { Fabricate ( :post , user : user , post_number : 1 ) }
let ( :p2 ) { Fabricate ( :post , user : user , post_number : 2 , topic : p1 . topic ) }
let! ( :topic ) { p1 . topic }
it " raises an error without post_ids " do
sign_in ( moderator )
post " /t/ #{ topic . id } /move-posts.json " , params : { title : 'blah' }
expect ( response . status ) . to eq ( 400 )
end
it " raises an error when the user doesn't have permission to move the posts " do
sign_in ( user )
post " /t/ #{ topic . id } /move-posts.json " , params : {
title : 'blah' , post_ids : [ p1 . post_number , p2 . post_number ]
}
expect ( response ) . to be_forbidden
end
it " raises an error when the OP is not a regular post " do
sign_in ( moderator )
p2 = Fabricate ( :post , topic : topic , post_number : 2 , post_type : Post . types [ :whisper ] )
p3 = Fabricate ( :post , topic : topic , post_number : 3 )
post " /t/ #{ topic . id } /move-posts.json " , params : {
title : 'blah' , post_ids : [ p2 . id , p3 . id ]
}
expect ( response . status ) . to eq ( 422 )
result = :: JSON . parse ( response . body )
expect ( result [ 'errors' ] ) . to be_present
end
context 'success' do
2019-05-06 18:00:22 +08:00
before { sign_in ( admin ) }
2018-05-31 22:45:32 +08:00
it " returns success " do
expect do
post " /t/ #{ topic . id } /move-posts.json " , params : {
title : 'Logan is a good movie' ,
post_ids : [ p2 . id ] ,
2018-07-07 00:21:32 +08:00
category_id : 123 ,
tags : [ " tag1 " , " tag2 " ]
2018-05-31 22:45:32 +08:00
}
end . to change { Topic . count } . by ( 1 )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to eq ( Topic . last . relative_url )
2018-07-09 09:54:14 +08:00
expect ( Tag . all . pluck ( :name ) ) . to contain_exactly ( " tag1 " , " tag2 " )
2018-05-31 22:45:32 +08:00
end
describe 'when topic has been deleted' do
it 'should still be able to move posts' do
2019-05-06 18:00:22 +08:00
PostDestroyer . new ( admin , topic . first_post ) . destroy
2018-05-31 22:45:32 +08:00
expect ( topic . reload . deleted_at ) . to_not be_nil
expect do
post " /t/ #{ topic . id } /move-posts.json " , params : {
title : 'Logan is a good movie' ,
post_ids : [ p2 . id ] ,
category_id : 123
}
end . to change { Topic . count } . by ( 1 )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to eq ( Topic . last . relative_url )
end
end
end
context 'failure' do
it " returns JSON with a false success " do
sign_in ( moderator )
post " /t/ #{ topic . id } /move-posts.json " , params : {
post_ids : [ p2 . id ]
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( false )
expect ( result [ 'url' ] ) . to be_blank
end
end
describe " moving replied posts " do
context 'success' do
it " moves the child posts too " do
2019-05-08 17:06:54 +08:00
user = sign_in ( moderator )
2018-05-31 22:45:32 +08:00
p1 = Fabricate ( :post , topic : topic , user : user )
p2 = Fabricate ( :post , topic : topic , user : user , reply_to_post_number : p1 . post_number )
2020-01-18 00:24:49 +08:00
PostReply . create ( post_id : p1 . id , reply_post_id : p2 . id )
2018-05-31 22:45:32 +08:00
post " /t/ #{ topic . id } /move-posts.json " , params : {
title : 'new topic title' ,
post_ids : [ p1 . id ] ,
reply_post_ids : [ p1 . id ]
}
expect ( response . status ) . to eq ( 200 )
p1 . reload
p2 . reload
new_topic_id = JSON . parse ( response . body ) [ " url " ] . split ( " / " ) . last . to_i
new_topic = Topic . find ( new_topic_id )
expect ( p1 . topic . id ) . to eq ( new_topic . id )
expect ( p2 . topic . id ) . to eq ( new_topic . id )
expect ( p2 . reply_to_post_number ) . to eq ( p1 . post_number )
end
end
end
end
describe 'moving to an existing topic' do
2019-05-08 17:06:54 +08:00
let! ( :user ) { sign_in ( moderator ) }
2018-05-31 22:45:32 +08:00
let ( :p1 ) { Fabricate ( :post , user : user ) }
let ( :topic ) { p1 . topic }
2019-05-07 11:12:20 +08:00
fab! ( :dest_topic ) { Fabricate ( :topic ) }
2018-05-31 22:45:32 +08:00
let ( :p2 ) { Fabricate ( :post , user : user , topic : topic ) }
context 'success' do
it " returns success " do
user
post " /t/ #{ topic . id } /move-posts.json " , params : {
post_ids : [ p2 . id ] ,
destination_topic_id : dest_topic . id
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
2018-07-10 09:48:57 +08:00
2018-07-10 09:28:57 +08:00
it " triggers an event on merge " do
2018-07-10 11:27:03 +08:00
begin
called = false
assert = - > ( original_topic , destination_topic ) do
called = true
expect ( original_topic ) . to eq ( topic )
expect ( destination_topic ) . to eq ( dest_topic )
end
DiscourseEvent . on ( :topic_merged , & assert )
post " /t/ #{ topic . id } /move-posts.json " , params : {
post_ids : [ p2 . id ] ,
destination_topic_id : dest_topic . id
}
expect ( called ) . to eq ( true )
expect ( response . status ) . to eq ( 200 )
ensure
DiscourseEvent . off ( :topic_merged , & assert )
2018-07-10 09:28:57 +08:00
end
end
2018-05-31 22:45:32 +08:00
end
context 'failure' do
let ( :p2 ) { Fabricate ( :post , user : user ) }
it " returns JSON with a false success " do
post " /t/ #{ topic . id } /move-posts.json " , params : {
post_ids : [ p2 . id ]
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( false )
expect ( result [ 'url' ] ) . to be_blank
end
end
end
2018-12-31 19:47:22 +08:00
describe 'moving to a new message' do
let! ( :message ) { Fabricate ( :private_message_topic ) }
let! ( :p1 ) { Fabricate ( :post , user : user , post_number : 1 , topic : message ) }
let! ( :p2 ) { Fabricate ( :post , user : user , post_number : 2 , topic : message ) }
it " raises an error without post_ids " do
sign_in ( moderator )
post " /t/ #{ message . id } /move-posts.json " , params : { title : 'blah' , archetype : 'private_message' }
expect ( response . status ) . to eq ( 400 )
end
it " raises an error when the user doesn't have permission to move the posts " do
sign_in ( trust_level_4 )
post " /t/ #{ message . id } /move-posts.json " , params : {
title : 'blah' , post_ids : [ p1 . post_number , p2 . post_number ] , archetype : 'private_message'
}
expect ( response . status ) . to eq ( 403 )
result = :: JSON . parse ( response . body )
expect ( result [ 'errors' ] ) . to be_present
end
context 'success' do
2019-05-06 18:00:22 +08:00
before { sign_in ( admin ) }
2018-12-31 19:47:22 +08:00
it " returns success " do
SiteSetting . allow_staff_to_tag_pms = true
expect do
post " /t/ #{ message . id } /move-posts.json " , params : {
title : 'Logan is a good movie' ,
post_ids : [ p2 . id ] ,
archetype : 'private_message' ,
tags : [ " tag1 " , " tag2 " ]
}
end . to change { Topic . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to eq ( Topic . last . relative_url )
expect ( Tag . all . pluck ( :name ) ) . to contain_exactly ( " tag1 " , " tag2 " )
end
describe 'when message has been deleted' do
it 'should still be able to move posts' do
2019-05-06 18:00:22 +08:00
PostDestroyer . new ( admin , message . first_post ) . destroy
2018-12-31 19:47:22 +08:00
expect ( message . reload . deleted_at ) . to_not be_nil
expect do
post " /t/ #{ message . id } /move-posts.json " , params : {
title : 'Logan is a good movie' ,
post_ids : [ p2 . id ] ,
archetype : 'private_message'
}
end . to change { Topic . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
result = JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to eq ( Topic . last . relative_url )
end
end
end
context 'failure' do
it " returns JSON with a false success " do
sign_in ( moderator )
post " /t/ #{ message . id } /move-posts.json " , params : {
post_ids : [ p2 . id ] ,
archetype : 'private_message'
}
expect ( response . status ) . to eq ( 200 )
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( false )
expect ( result [ 'url' ] ) . to be_blank
end
end
end
describe 'moving to an existing message' do
2019-05-06 18:00:22 +08:00
let! ( :user ) { sign_in ( admin ) }
2019-05-07 11:12:20 +08:00
fab! ( :evil_trout ) { Fabricate ( :evil_trout ) }
2018-12-31 19:47:22 +08:00
let ( :message ) { Fabricate ( :private_message_topic ) }
let ( :p2 ) { Fabricate ( :post , user : evil_trout , post_number : 2 , topic : message ) }
let ( :dest_message ) do
Fabricate ( :private_message_topic , user : trust_level_4 , topic_allowed_users : [
Fabricate . build ( :topic_allowed_user , user : evil_trout )
] )
end
context 'success' do
it " returns success " do
user
post " /t/ #{ message . id } /move-posts.json " , params : {
post_ids : [ p2 . id ] ,
destination_topic_id : dest_message . id ,
archetype : 'private_message'
}
expect ( response . status ) . to eq ( 200 )
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
end
context 'failure' do
it " returns JSON with a false success " do
post " /t/ #{ message . id } /move-posts.json " , params : {
post_ids : [ p2 . id ] ,
archetype : 'private_message'
}
expect ( response . status ) . to eq ( 200 )
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( false )
expect ( result [ 'url' ] ) . to be_blank
end
end
end
2018-05-31 22:45:32 +08:00
end
describe '#merge_topic' do
it 'needs you to be logged in' do
post " /t/111/merge-topic.json " , params : {
destination_topic_id : 345
}
expect ( response . status ) . to eq ( 403 )
end
2018-12-31 19:47:22 +08:00
describe 'merging into another topic' do
2018-05-31 22:45:32 +08:00
let ( :p1 ) { Fabricate ( :post , user : user ) }
let ( :topic ) { p1 . topic }
it " raises an error without destination_topic_id " do
sign_in ( moderator )
post " /t/ #{ topic . id } /merge-topic.json "
expect ( response . status ) . to eq ( 400 )
end
it " raises an error when the user doesn't have permission to merge " do
sign_in ( user )
post " /t/111/merge-topic.json " , params : { destination_topic_id : 345 }
expect ( response ) . to be_forbidden
end
let ( :dest_topic ) { Fabricate ( :topic ) }
context 'moves all the posts to the destination topic' do
it " returns success " do
sign_in ( moderator )
post " /t/ #{ topic . id } /merge-topic.json " , params : {
destination_topic_id : dest_topic . id
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
2018-12-31 19:47:22 +08:00
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
end
end
describe 'merging into another message' do
let ( :message ) { Fabricate ( :private_message_topic , user : user ) }
let! ( :p1 ) { Fabricate ( :post , topic : message , user : trust_level_4 ) }
let! ( :p2 ) { Fabricate ( :post , topic : message , reply_to_post_number : p1 . post_number , user : user ) }
it " raises an error without destination_topic_id " do
sign_in ( moderator )
post " /t/ #{ message . id } /merge-topic.json " , params : {
archetype : 'private_message'
}
expect ( response . status ) . to eq ( 400 )
end
it " raises an error when the user doesn't have permission to merge " do
sign_in ( trust_level_4 )
post " /t/ #{ message . id } /merge-topic.json " , params : {
destination_topic_id : 345 ,
archetype : 'private_message'
}
expect ( response ) . to be_forbidden
end
let ( :dest_message ) do
Fabricate ( :private_message_topic , user : trust_level_4 , topic_allowed_users : [
Fabricate . build ( :topic_allowed_user , user : moderator )
] )
end
context 'moves all the posts to the destination message' do
it " returns success " do
sign_in ( moderator )
post " /t/ #{ message . id } /merge-topic.json " , params : {
destination_topic_id : dest_message . id ,
archetype : 'private_message'
}
expect ( response . status ) . to eq ( 200 )
result = :: JSON . parse ( response . body )
2018-05-31 22:45:32 +08:00
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
end
end
end
describe '#change_post_owners' do
it 'needs you to be logged in' do
post " /t/111/change-owner.json " , params : {
username : 'user_a' ,
post_ids : [ 1 , 2 , 3 ]
}
expect ( response ) . to be_forbidden
end
describe 'forbidden to moderators' do
before do
2019-05-08 17:06:54 +08:00
sign_in ( moderator )
2018-05-31 22:45:32 +08:00
end
it 'correctly denies' do
post " /t/111/change-owner.json " , params : {
topic_id : 111 , username : 'user_a' , post_ids : [ 1 , 2 , 3 ]
}
expect ( response ) . to be_forbidden
end
end
describe 'forbidden to trust_level_4s' do
before do
2019-05-06 19:19:50 +08:00
sign_in ( trust_level_4 )
2018-05-31 22:45:32 +08:00
end
it 'correctly denies' do
post " /t/111/change-owner.json " , params : {
topic_id : 111 , username : 'user_a' , post_ids : [ 1 , 2 , 3 ]
}
expect ( response ) . to be_forbidden
end
end
describe 'changing ownership' do
2019-05-06 18:00:22 +08:00
let! ( :editor ) { sign_in ( admin ) }
2018-05-31 22:45:32 +08:00
let ( :topic ) { Fabricate ( :topic ) }
2019-05-07 11:12:20 +08:00
fab! ( :user_a ) { Fabricate ( :user ) }
2018-06-05 15:29:17 +08:00
let ( :p1 ) { Fabricate ( :post , topic : topic ) }
let ( :p2 ) { Fabricate ( :post , topic : topic ) }
2018-05-31 22:45:32 +08:00
it " raises an error with a parameter missing " do
[
{ post_ids : [ 1 , 2 , 3 ] } ,
{ username : 'user_a' }
] . each do | params |
post " /t/111/change-owner.json " , params : params
expect ( response . status ) . to eq ( 400 )
end
end
it " changes the topic and posts ownership " do
post " /t/ #{ topic . id } /change-owner.json " , params : {
username : user_a . username_lower , post_ids : [ p1 . id ]
}
topic . reload
p1 . reload
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( topic . user . username ) . to eq ( user_a . username )
expect ( p1 . user . username ) . to eq ( user_a . username )
end
it " changes multiple posts " do
post " /t/ #{ topic . id } /change-owner.json " , params : {
username : user_a . username_lower , post_ids : [ p1 . id , p2 . id ]
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
p1 . reload
p2 . reload
expect ( p1 . user ) . to_not eq ( nil )
expect ( p1 . reload . user ) . to eq ( p2 . reload . user )
end
it " works with deleted users " do
2019-05-06 17:44:15 +08:00
deleted_user = user
2018-05-31 22:45:32 +08:00
t2 = Fabricate ( :topic , user : deleted_user )
2018-06-05 15:29:17 +08:00
p3 = Fabricate ( :post , topic : t2 , user : deleted_user )
2018-05-31 22:45:32 +08:00
UserDestroyer . new ( editor ) . destroy ( deleted_user , delete_posts : true , context : 'test' , delete_as_spammer : true )
post " /t/ #{ t2 . id } /change-owner.json " , params : {
username : user_a . username_lower , post_ids : [ p3 . id ]
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
t2 . reload
p3 . reload
expect ( t2 . deleted_at ) . to be_nil
expect ( p3 . user ) . to eq ( user_a )
end
end
end
describe '#change_timestamps' do
let ( :params ) { { timestamp : Time . zone . now } }
it 'needs you to be logged in' do
put " /t/1/change-timestamp.json " , params : params
expect ( response . status ) . to eq ( 403 )
end
2019-02-22 17:03:52 +08:00
describe " forbidden to trust_level_4 " do
2019-05-06 19:19:50 +08:00
before do
sign_in ( trust_level_4 )
end
2018-05-31 22:45:32 +08:00
2019-02-22 17:03:52 +08:00
it 'correctly denies' do
put " /t/1/change-timestamp.json " , params : params
expect ( response ) . to be_forbidden
2018-05-31 22:45:32 +08:00
end
end
describe 'changing timestamps' do
2020-03-11 05:13:17 +08:00
before do
freeze_time
sign_in ( moderator )
end
2018-05-31 22:45:32 +08:00
let ( :old_timestamp ) { Time . zone . now }
let ( :new_timestamp ) { old_timestamp - 1 . day }
let! ( :topic ) { Fabricate ( :topic , created_at : old_timestamp ) }
2018-06-05 15:29:17 +08:00
let! ( :p1 ) { Fabricate ( :post , topic : topic , created_at : old_timestamp ) }
let! ( :p2 ) { Fabricate ( :post , topic : topic , created_at : old_timestamp + 1 . day ) }
2018-05-31 22:45:32 +08:00
2018-06-05 15:29:17 +08:00
it 'should update the timestamps of selected posts' do
# try to see if we fail with invalid first
2018-05-31 22:45:32 +08:00
put " /t/1/change-timestamp.json "
expect ( response . status ) . to eq ( 400 )
put " /t/ #{ topic . id } /change-timestamp.json " , params : {
timestamp : new_timestamp . to_f
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2020-03-11 05:13:17 +08:00
expect ( topic . reload . created_at ) . to eq_time ( new_timestamp )
expect ( p1 . reload . created_at ) . to eq_time ( new_timestamp )
expect ( p2 . reload . created_at ) . to eq_time ( old_timestamp )
2018-05-31 22:45:32 +08:00
end
2019-02-22 17:03:52 +08:00
it 'should create a staff log entry' do
put " /t/ #{ topic . id } /change-timestamp.json " , params : {
timestamp : new_timestamp . to_f
}
log = UserHistory . last
expect ( log . acting_user_id ) . to eq ( moderator . id )
expect ( log . topic_id ) . to eq ( topic . id )
expect ( log . new_value ) . to eq ( new_timestamp . utc . to_s )
expect ( log . previous_value ) . to eq ( old_timestamp . utc . to_s )
end
2018-05-31 22:45:32 +08:00
end
end
describe '#clear_pin' do
it 'needs you to be logged in' do
put " /t/1/clear-pin.json "
expect ( response . status ) . to eq ( 403 )
end
context 'when logged in' do
let ( :topic ) { Fabricate ( :topic ) }
let ( :pm ) { Fabricate ( :private_message_topic ) }
before do
sign_in ( user )
end
it " fails when the user can't see the topic " do
put " /t/ #{ pm . id } /clear-pin.json "
expect ( response ) . to be_forbidden
end
describe 'when the user can see the topic' do
it " succeeds " do
expect do
put " /t/ #{ topic . id } /clear-pin.json "
end . to change { TopicUser . where ( topic_id : topic . id , user_id : user . id ) . count } . by ( 1 )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
end
end
end
end
describe '#status' do
it 'needs you to be logged in' do
put " /t/1/status.json " , params : {
status : 'visible' , enabled : true
}
expect ( response . status ) . to eq ( 403 )
end
describe 'when logged in' do
let ( :topic ) { Fabricate ( :topic ) }
before do
sign_in ( moderator )
end
it " raises an exception if you can't change it " do
sign_in ( user )
put " /t/ #{ topic . id } /status.json " , params : {
status : 'visible' , enabled : 'true'
}
expect ( response ) . to be_forbidden
end
it 'requires the status parameter' do
put " /t/ #{ topic . id } /status.json " , params : { enabled : true }
expect ( response . status ) . to eq ( 400 )
end
it 'requires the enabled parameter' do
put " /t/ #{ topic . id } /status.json " , params : { status : 'visible' }
expect ( response . status ) . to eq ( 400 )
end
it 'raises an error with a status not in the whitelist' do
put " /t/ #{ topic . id } /status.json " , params : {
status : 'title' , enabled : 'true'
}
expect ( response . status ) . to eq ( 400 )
end
it 'should update the status of the topic correctly' do
2018-06-05 15:29:17 +08:00
topic = Fabricate ( :topic , user : user , closed : true )
Fabricate ( :topic_timer , topic : topic , status_type : TopicTimer . types [ :open ] )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /status.json " , params : {
status : 'closed' , enabled : 'false'
}
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( topic . reload . closed ) . to eq ( false )
expect ( topic . topic_timers ) . to eq ( [ ] )
body = JSON . parse ( response . body )
expect ( body [ 'topic_status_update' ] ) . to eq ( nil )
end
end
end
describe '#destroy_timings' do
it 'needs you to be logged in' do
delete " /t/1/timings.json "
expect ( response . status ) . to eq ( 403 )
end
def topic_user_post_timings_count ( user , topic )
[ TopicUser , PostTiming ] . map do | klass |
klass . where ( user : user , topic : topic ) . count
end
end
2018-11-13 13:07:48 +08:00
context 'for last post only' do
it 'should allow you to retain topic timing but remove last post only' do
2019-04-05 09:44:36 +08:00
freeze_time
2018-11-13 13:07:48 +08:00
post1 = create_post
2019-04-09 10:42:21 +08:00
user = post1 . user
2018-11-13 13:07:48 +08:00
topic = post1 . topic
post2 = create_post ( topic_id : topic . id )
PostTiming . create! ( topic : topic , user : user , post_number : 2 , msecs : 100 )
2019-04-05 09:44:36 +08:00
user . user_stat . update! ( first_unread_at : Time . now + 1 . week )
2019-04-09 10:42:21 +08:00
topic_user = TopicUser . find_by (
topic_id : topic . id ,
user_id : user . id ,
)
topic_user . update! (
2018-11-13 13:07:48 +08:00
last_read_post_number : 2 ,
highest_seen_post_number : 2
)
2019-04-09 10:42:21 +08:00
# ensure we have 2 notifications
# fake notification on topic but it is read
first_notification = Notification . create! (
user_id : user . id ,
topic_id : topic . id ,
data : " {} " ,
read : true ,
notification_type : 1
)
freeze_time 1 . minute . from_now
PostAlerter . post_created ( post2 )
second_notification = user . notifications . where ( topic_id : topic . id ) . order ( created_at : :desc ) . first
second_notification . update! ( read : true )
2018-11-13 13:07:48 +08:00
sign_in ( user )
delete " /t/ #{ topic . id } /timings.json?last=1 "
expect ( PostTiming . where ( topic : topic , user : user , post_number : 2 ) . exists? ) . to eq ( false )
expect ( PostTiming . where ( topic : topic , user : user , post_number : 1 ) . exists? ) . to eq ( true )
expect ( TopicUser . where ( topic : topic , user : user , last_read_post_number : 1 , highest_seen_post_number : 1 ) . exists? ) . to eq ( true )
2019-04-05 09:44:36 +08:00
user . user_stat . reload
expect ( user . user_stat . first_unread_at ) . to eq_time ( topic . updated_at )
2019-04-09 10:42:21 +08:00
first_notification . reload
second_notification . reload
expect ( first_notification . read ) . to eq ( true )
expect ( second_notification . read ) . to eq ( false )
2019-05-06 18:00:22 +08:00
PostDestroyer . new ( admin , post2 ) . destroy
2018-11-13 13:07:48 +08:00
delete " /t/ #{ topic . id } /timings.json?last=1 "
expect ( PostTiming . where ( topic : topic , user : user , post_number : 1 ) . exists? ) . to eq ( false )
expect ( TopicUser . where ( topic : topic , user : user , last_read_post_number : nil , highest_seen_post_number : nil ) . exists? ) . to eq ( true )
end
end
2018-05-31 22:45:32 +08:00
context 'when logged in' do
before do
2019-05-06 17:44:15 +08:00
@user = sign_in ( user )
2018-05-31 22:45:32 +08:00
@topic = Fabricate ( :topic , user : @user )
Fabricate ( :post , user : @user , topic : @topic , post_number : 2 )
TopicUser . create! ( topic : @topic , user : @user )
PostTiming . create! ( topic : @topic , user : @user , post_number : 2 , msecs : 1000 )
end
it 'deletes the forum topic user and post timings records' do
expect do
delete " /t/ #{ @topic . id } /timings.json "
end . to change { topic_user_post_timings_count ( @user , @topic ) } . from ( [ 1 , 1 ] ) . to ( [ 0 , 0 ] )
end
end
end
describe '#mute/unmute' do
it 'needs you to be logged in' do
put " /t/99/mute.json "
expect ( response . status ) . to eq ( 403 )
end
it 'needs you to be logged in' do
put " /t/99/unmute.json "
expect ( response . status ) . to eq ( 403 )
end
end
describe '#recover' do
it " won't allow us to recover a topic when we're not logged in " do
put " /t/1/recover.json "
expect ( response . status ) . to eq ( 403 )
end
describe 'when logged in' do
let ( :topic ) { Fabricate ( :topic , user : user , deleted_at : Time . now , deleted_by : moderator ) }
let! ( :post ) { Fabricate ( :post , user : user , topic : topic , post_number : 1 , deleted_at : Time . now , deleted_by : moderator ) }
describe 'without access' do
it " raises an exception when the user doesn't have permission to delete the topic " do
sign_in ( user )
put " /t/ #{ topic . id } /recover.json "
expect ( response ) . to be_forbidden
end
end
context 'with permission' do
before do
sign_in ( moderator )
end
it 'succeeds' do
put " /t/ #{ topic . id } /recover.json "
topic . reload
post . reload
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( topic . trashed? ) . to be_falsey
expect ( post . trashed? ) . to be_falsey
end
end
end
end
describe '#delete' do
it " won't allow us to delete a topic when we're not logged in " do
delete " /t/1.json "
expect ( response . status ) . to eq ( 403 )
end
describe 'when logged in' do
2019-03-30 00:10:05 +08:00
let ( :topic ) { Fabricate ( :topic , user : user , created_at : 48 . hours . ago ) }
2018-05-31 22:45:32 +08:00
let! ( :post ) { Fabricate ( :post , topic : topic , user : user , post_number : 1 ) }
describe 'without access' do
it " raises an exception when the user doesn't have permission to delete the topic " do
sign_in ( user )
delete " /t/ #{ topic . id } .json "
2020-01-15 21:41:41 +08:00
expect ( response . status ) . to eq ( 422 )
2018-05-31 22:45:32 +08:00
end
end
describe 'with permission' do
before do
sign_in ( moderator )
end
it 'succeeds' do
delete " /t/ #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
topic . reload
expect ( topic . trashed? ) . to be_truthy
end
end
end
end
describe '#id_for_slug' do
let ( :topic ) { Fabricate ( :post ) . topic }
let ( :pm ) { Fabricate ( :private_message_topic ) }
it " returns JSON for the slug " do
get " /t/id_for/ #{ topic . slug } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
json = :: JSON . parse ( response . body )
expect ( json [ 'topic_id' ] ) . to eq ( topic . id )
expect ( json [ 'url' ] ) . to eq ( topic . url )
expect ( json [ 'slug' ] ) . to eq ( topic . slug )
end
it " returns invalid access if the user can't see the topic " do
get " /t/id_for/ #{ pm . slug } .json "
expect ( response ) . to be_forbidden
end
end
2018-03-02 09:13:04 +08:00
describe '#update' do
2018-03-13 10:20:47 +08:00
it " won't allow us to update a topic when we're not logged in " do
put " /t/1.json " , params : { slug : 'xyz' }
expect ( response . status ) . to eq ( 403 )
end
describe 'when logged in' do
let ( :topic ) { Fabricate ( :topic , user : user ) }
2018-03-02 09:13:04 +08:00
2018-03-13 10:20:47 +08:00
before do
Fabricate ( :post , topic : topic )
2018-05-31 22:45:32 +08:00
SiteSetting . editing_grace_period = 0
2018-03-13 10:20:47 +08:00
sign_in ( user )
end
2018-03-02 09:13:04 +08:00
2018-03-13 10:20:47 +08:00
it 'can not change category to a disallowed category' do
category = Fabricate ( :category )
category . set_permissions ( staff : :full )
category . save!
2018-03-02 09:13:04 +08:00
2018-03-13 10:20:47 +08:00
put " /t/ #{ topic . id } .json " , params : { category_id : category . id }
2018-07-13 10:51:08 +08:00
expect ( response . status ) . to eq ( 403 )
expect ( topic . reload . category_id ) . not_to eq ( category . id )
end
it 'can not move to a category that requires topic approval' do
category = Fabricate ( :category )
category . custom_fields [ Category :: REQUIRE_TOPIC_APPROVAL ] = true
category . save!
put " /t/ #{ topic . id } .json " , params : { category_id : category . id }
expect ( response . status ) . to eq ( 403 )
expect ( topic . reload . category_id ) . not_to eq ( category . id )
2018-03-13 10:20:47 +08:00
end
describe 'without permission' do
it " raises an exception when the user doesn't have permission to update the topic " do
topic . update! ( archived : true )
put " /t/ #{ topic . slug } / #{ topic . id } .json "
expect ( response . status ) . to eq ( 403 )
end
end
describe 'with permission' do
it 'succeeds' do
put " /t/ #{ topic . slug } / #{ topic . id } .json "
expect ( response . status ) . to eq ( 200 )
expect ( :: JSON . parse ( response . body ) [ 'basic_topic' ] ) . to be_present
end
it " can update a topic to an uncategorized topic " do
topic . update! ( category : Fabricate ( :category ) )
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : " "
}
expect ( response . status ) . to eq ( 200 )
expect ( topic . reload . category_id ) . to eq ( SiteSetting . uncategorized_category_id )
end
it 'allows a change of title' do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
title : 'This is a new title for the topic'
}
topic . reload
expect ( topic . title ) . to eq ( 'This is a new title for the topic' )
end
it " returns errors with invalid titles " do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
title : 'asdf'
}
expect ( response . status ) . to eq ( 422 )
expect ( JSON . parse ( response . body ) [ 'errors' ] ) . to be_present
end
2018-03-02 09:13:04 +08:00
2018-03-13 10:20:47 +08:00
it " returns errors when the rate limit is exceeded " do
EditRateLimiter . any_instance . expects ( :performed! ) . raises ( RateLimiter :: LimitExceeded . new ( 60 ) )
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
title : 'This is a new title for the topic'
}
expect ( response . status ) . to eq ( 429 )
end
it " returns errors with invalid categories " do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : - 1
}
expect ( response . status ) . to eq ( 422 )
end
it " doesn't call the PostRevisor when there is no changes " do
2018-05-31 22:45:32 +08:00
expect do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
2019-05-17 16:26:00 +08:00
category_id : topic . category_id
2018-05-31 22:45:32 +08:00
}
end . not_to change ( PostRevision . all , :count )
2018-03-13 10:20:47 +08:00
expect ( response . status ) . to eq ( 200 )
end
2019-05-17 16:26:00 +08:00
context 'tags' do
fab! ( :tag ) { Fabricate ( :tag ) }
before do
SiteSetting . tagging_enabled = true
end
it " can add a tag to topic " do
expect do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
tags : [ tag . name ]
}
end . to change { topic . reload . first_post . revisions . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
expect ( topic . tags . pluck ( :id ) ) . to contain_exactly ( tag . id )
end
2019-10-24 02:05:38 +08:00
it " can add a tag to wiki topic " do
SiteSetting . min_trust_to_edit_wiki_post = 2
topic . first_post . update! ( wiki : true )
user = Fabricate ( :user )
sign_in ( user )
expect do
put " /t/ #{ topic . id } /tags.json " , params : {
tags : [ tag . name ]
}
end . not_to change { topic . reload . first_post . revisions . count }
expect ( response . status ) . to eq ( 403 )
user . update! ( trust_level : 2 )
expect do
put " /t/ #{ topic . id } /tags.json " , params : {
tags : [ tag . name ]
}
end . to change { topic . reload . first_post . revisions . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
expect ( topic . tags . pluck ( :id ) ) . to contain_exactly ( tag . id )
end
2019-05-17 16:26:00 +08:00
it 'does not remove tag if no params is given' do
topic . tags << tag
expect do
put " /t/ #{ topic . slug } / #{ topic . id } .json "
end . to_not change { topic . reload . tags . count }
expect ( response . status ) . to eq ( 200 )
end
it 'can remove a tag' do
topic . tags << tag
expect do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
tags : [ " " ]
}
end . to change { topic . reload . first_post . revisions . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
expect ( topic . tags ) . to eq ( [ ] )
end
end
2018-03-13 10:20:47 +08:00
context 'when topic is private' do
before do
topic . update! (
archetype : Archetype . private_message ,
category : nil ,
allowed_users : [ topic . user ]
)
end
context 'when there are no changes' do
it 'does not call the PostRevisor' do
2018-05-31 22:45:32 +08:00
expect do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : topic . category_id
}
end . not_to change ( PostRevision . all , :count )
2018-03-13 10:20:47 +08:00
expect ( response . status ) . to eq ( 200 )
end
end
end
2019-02-26 18:21:55 +08:00
context 'updating to a category with restricted tags' do
2019-05-07 11:12:20 +08:00
fab! ( :category ) { Fabricate ( :category ) }
fab! ( :restricted_category ) { Fabricate ( :category ) }
fab! ( :tag1 ) { Fabricate ( :tag ) }
fab! ( :tag2 ) { Fabricate ( :tag ) }
2019-11-13 03:28:44 +08:00
let ( :tag3 ) { Fabricate ( :tag ) }
2019-03-11 22:02:27 +08:00
let! ( :tag_group_1 ) { Fabricate ( :tag_group , tag_names : [ tag1 . name ] ) }
2019-05-07 11:12:20 +08:00
fab! ( :tag_group_2 ) { Fabricate ( :tag_group ) }
2019-02-26 18:21:55 +08:00
before do
SiteSetting . tagging_enabled = true
topic . update! ( tags : [ tag1 ] )
end
2019-03-11 22:02:27 +08:00
it 'can’ t change to a category disallowing this topic current tags' do
2019-02-26 18:21:55 +08:00
restricted_category . allowed_tags = [ tag2 . name ]
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { category_id : restricted_category . id }
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 422 )
expect ( result [ 'errors' ] ) . to be_present
expect ( topic . reload . category_id ) . not_to eq ( restricted_category . id )
end
2019-03-11 22:02:27 +08:00
it 'can’ t change to a category disallowing this topic current tag (through tag_group)' do
tag_group_2 . tags = [ tag2 ]
restricted_category . allowed_tag_groups = [ tag_group_2 . name ]
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { category_id : restricted_category . id }
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 422 )
expect ( result [ 'errors' ] ) . to be_present
expect ( topic . reload . category_id ) . not_to eq ( restricted_category . id )
end
2019-02-26 18:21:55 +08:00
it 'can change to a category allowing this topic current tags' do
restricted_category . allowed_tags = [ tag1 . name ]
2019-03-11 22:02:27 +08:00
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { category_id : restricted_category . id }
expect ( response . status ) . to eq ( 200 )
end
it 'can change to a category allowing this topic current tags (through tag_group)' do
tag_group_1 . tags = [ tag1 ]
restricted_category . allowed_tag_groups = [ tag_group_1 . name ]
2019-02-26 18:21:55 +08:00
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { category_id : restricted_category . id }
expect ( response . status ) . to eq ( 200 )
end
it 'can change to a category allowing any tag' do
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { category_id : category . id }
expect ( response . status ) . to eq ( 200 )
end
2019-07-23 23:06:25 +08:00
it 'can’ t add a category-only tags from another category to a category' do
restricted_category . allowed_tags = [ tag2 . name ]
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
2019-08-22 04:33:01 +08:00
tags : [ tag2 . name ] ,
2019-07-23 23:06:25 +08:00
category_id : category . id
}
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 422 )
expect ( result [ 'errors' ] ) . to be_present
2019-08-22 04:33:01 +08:00
expect ( result [ 'errors' ] [ 0 ] ) . to include ( tag2 . name )
2019-07-23 23:06:25 +08:00
expect ( topic . reload . category_id ) . not_to eq ( restricted_category . id )
end
2019-08-22 04:33:01 +08:00
it 'allows category change when topic has a hidden tag' do
Fabricate ( :tag_group , permissions : { " staff " = > 1 } , tag_names : [ tag1 . name ] )
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : category . id
}
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 200 )
expect ( topic . reload . tags ) . to include ( tag1 )
end
it 'allows category change when topic has a read-only tag' do
2019-11-13 03:28:44 +08:00
Fabricate ( :tag_group , permissions : { " staff " = > 1 , " everyone " = > 3 } , tag_names : [ tag3 . name ] )
topic . update! ( tags : [ tag3 ] )
2019-08-22 04:33:01 +08:00
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : category . id
}
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 200 )
2019-11-13 03:28:44 +08:00
expect ( topic . reload . tags ) . to contain_exactly ( tag3 )
2019-08-22 04:33:01 +08:00
end
it 'does not leak tag name when trying to use a staff tag' do
2019-11-13 03:28:44 +08:00
Fabricate ( :tag_group , permissions : { " staff " = > 1 } , tag_names : [ tag3 . name ] )
2019-08-22 04:33:01 +08:00
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
2019-11-13 03:28:44 +08:00
tags : [ tag3 . name ] ,
2019-08-22 04:33:01 +08:00
category_id : category . id
}
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 422 )
expect ( result [ 'errors' ] ) . to be_present
2019-11-13 03:28:44 +08:00
expect ( result [ 'errors' ] [ 0 ] ) . not_to include ( tag3 . name )
2019-08-22 04:33:01 +08:00
end
2019-07-23 23:06:25 +08:00
it 'will clean tag params' do
restricted_category . allowed_tags = [ tag2 . name ]
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
tags : [ " " ] ,
category_id : restricted_category . id
}
result = :: JSON . parse ( response . body )
expect ( response . status ) . to eq ( 200 )
end
2019-02-26 18:21:55 +08:00
end
2018-03-13 10:20:47 +08:00
context " allow_uncategorized_topics is false " do
before do
SiteSetting . allow_uncategorized_topics = false
end
it " can add a category to an uncategorized topic " do
category = Fabricate ( :category )
put " /t/ #{ topic . slug } / #{ topic . id } .json " , params : {
category_id : category . id
}
expect ( response . status ) . to eq ( 200 )
expect ( topic . reload . category ) . to eq ( category )
end
end
end
end
2018-03-02 09:13:04 +08:00
end
2017-09-28 11:04:17 +08:00
describe '#show' do
let ( :private_topic ) { Fabricate ( :private_message_topic ) }
2018-05-31 22:45:32 +08:00
let ( :topic ) { Fabricate ( :post ) . topic }
let! ( :p1 ) { Fabricate ( :post , user : topic . user ) }
let! ( :p2 ) { Fabricate ( :post , user : topic . user ) }
2017-09-28 11:04:17 +08:00
describe 'when topic is not allowed' do
it 'should return the right response' do
2019-10-08 19:15:08 +08:00
SiteSetting . detailed_404 = true
2017-09-28 11:04:17 +08:00
sign_in ( user )
get " /t/ #{ private_topic . id } .json "
expect ( response . status ) . to eq ( 403 )
2019-10-08 19:15:08 +08:00
expect ( response . body ) . to include ( I18n . t ( 'invalid_access' ) )
2017-09-28 11:04:17 +08:00
end
end
2018-05-31 22:45:32 +08:00
it 'correctly renders canoicals' do
get " /t/ #{ topic . id } " , params : { slug : topic . slug }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( css_select ( " link[rel=canonical] " ) . length ) . to eq ( 1 )
2018-06-05 15:29:17 +08:00
expect ( response . headers [ " Cache-Control " ] ) . to eq ( " no-cache, no-store " )
2018-05-31 22:45:32 +08:00
end
it 'returns 301 even if slug does not match URL' do
# in the past we had special logic for unlisted topics
# we would require slug unless you made a json call
# this was not really providing any security
#
# we no longer require a topic be visible to perform url correction
# if you need to properly hide a topic for users use a secure category
# or a PM
topic = Fabricate ( :topic , visible : false )
Fabricate ( :post , topic : topic )
get " /t/ #{ topic . id } .json " , params : { slug : topic . slug }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
get " /t/ #{ topic . id } .json " , params : { slug : " just-guessing " }
expect ( response . status ) . to eq ( 301 )
get " /t/ #{ topic . slug } .json "
expect ( response . status ) . to eq ( 301 )
end
it 'shows a topic correctly' do
get " /t/ #{ topic . slug } / #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
end
it 'return 404 for an invalid page' do
get " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { page : 2 }
expect ( response . status ) . to eq ( 404 )
end
it 'can find a topic given a slug in the id param' do
get " /t/ #{ topic . slug } "
expect ( response ) . to redirect_to ( topic . relative_url )
end
it 'can find a topic when a slug has a number in front' do
another_topic = Fabricate ( :post ) . topic
topic . update_column ( :slug , " #{ another_topic . id } -reasons-discourse-is-awesome " )
get " /t/ #{ another_topic . id } -reasons-discourse-is-awesome "
expect ( response ) . to redirect_to ( topic . relative_url )
end
it 'keeps the post_number parameter around when redirecting' do
get " /t/ #{ topic . slug } " , params : { post_number : 42 }
expect ( response ) . to redirect_to ( topic . relative_url + " /42 " )
end
it 'keeps the page around when redirecting' do
get " /t/ #{ topic . slug } " , params : {
post_number : 42 , page : 123
}
expect ( response ) . to redirect_to ( topic . relative_url + " /42?page=123 " )
end
it 'does not accept page params as an array' do
get " /t/ #{ topic . slug } " , params : {
post_number : 42 , page : [ 2 ]
}
expect ( response ) . to redirect_to ( " #{ topic . relative_url } /42?page=1 " )
end
it 'returns 404 when an invalid slug is given and no id' do
get " /t/nope-nope.json "
expect ( response . status ) . to eq ( 404 )
end
it 'returns a 404 when slug and topic id do not match a topic' do
get " /t/made-up-topic-slug/123456.json "
expect ( response . status ) . to eq ( 404 )
end
it 'returns a 404 for an ID that is larger than postgres limits' do
get " /t/made-up-topic-slug/5014217323220164041.json "
expect ( response . status ) . to eq ( 404 )
end
context 'a topic with nil slug exists' do
before do
nil_slug_topic = Fabricate ( :topic )
Topic . connection . execute ( " update topics set slug=null where id = #{ nil_slug_topic . id } " ) # can't find a way to set slug column to null using the model
end
it 'returns a 404 when slug and topic id do not match a topic' do
get " /t/made-up-topic-slug/123123.json "
expect ( response . status ) . to eq ( 404 )
end
end
context 'permission errors' do
2019-05-07 11:12:20 +08:00
fab! ( :allowed_user ) { Fabricate ( :user ) }
2018-05-31 22:45:32 +08:00
let ( :allowed_group ) { Fabricate ( :group ) }
2019-07-04 16:12:39 +08:00
let ( :accessible_group ) { Fabricate ( :group , public_admission : true ) }
2018-05-31 22:45:32 +08:00
let ( :secure_category ) do
c = Fabricate ( :category )
c . permissions = [ [ allowed_group , :full ] ]
c . save
allowed_user . groups = [ allowed_group ]
allowed_user . save
c
end
2019-07-04 16:12:39 +08:00
let ( :accessible_category ) do
Fabricate ( :category ) . tap do | c |
c . set_permissions ( accessible_group = > :full )
c . save!
end
end
2018-05-31 22:45:32 +08:00
let ( :normal_topic ) { Fabricate ( :topic ) }
let ( :secure_topic ) { Fabricate ( :topic , category : secure_category ) }
let ( :private_topic ) { Fabricate ( :private_message_topic , user : allowed_user ) }
let ( :deleted_topic ) { Fabricate ( :deleted_topic ) }
let ( :deleted_secure_topic ) { Fabricate ( :topic , category : secure_category , deleted_at : 1 . day . ago ) }
let ( :deleted_private_topic ) { Fabricate ( :private_message_topic , user : allowed_user , deleted_at : 1 . day . ago ) }
let ( :nonexist_topic_id ) { Topic . last . id + 10000 }
2019-07-04 16:12:39 +08:00
let ( :secure_accessible_topic ) { Fabricate ( :topic , category : accessible_category ) }
2018-05-31 22:45:32 +08:00
shared_examples " various scenarios " do | expected |
expected . each do | key , value |
it " returns #{ value } for #{ key } " do
slug = key == :nonexist ? " garbage-slug " : eval ( key . to_s ) . slug
topic_id = key == :nonexist ? nonexist_topic_id : eval ( key . to_s ) . id
get " /t/ #{ slug } / #{ topic_id } .json "
expect ( response . status ) . to eq ( value )
end
end
end
2019-10-08 19:15:08 +08:00
context 'without detailed error pages' do
2018-05-31 22:45:32 +08:00
before do
2019-10-08 19:15:08 +08:00
SiteSetting . detailed_404 = false
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'anonymous' do
expected = {
normal_topic : 200 ,
secure_topic : 404 ,
private_topic : 404 ,
deleted_topic : 404 ,
deleted_secure_topic : 404 ,
deleted_private_topic : 404 ,
nonexist : 404 ,
secure_accessible_topic : 404
}
include_examples " various scenarios " , expected
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'anonymous with login required' do
before do
SiteSetting . login_required = true
end
expected = {
normal_topic : 302 ,
secure_topic : 302 ,
private_topic : 302 ,
deleted_topic : 302 ,
deleted_secure_topic : 302 ,
deleted_private_topic : 302 ,
nonexist : 302 ,
secure_accessible_topic : 302
}
include_examples " various scenarios " , expected
end
2018-05-31 22:45:32 +08:00
2019-10-08 19:15:08 +08:00
context 'normal user' do
before do
sign_in ( user )
end
expected = {
normal_topic : 200 ,
secure_topic : 404 ,
private_topic : 404 ,
deleted_topic : 404 ,
deleted_secure_topic : 404 ,
deleted_private_topic : 404 ,
nonexist : 404 ,
secure_accessible_topic : 404
}
include_examples " various scenarios " , expected
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'allowed user' do
before do
sign_in ( allowed_user )
end
2018-05-31 22:45:32 +08:00
2019-10-08 19:15:08 +08:00
expected = {
normal_topic : 200 ,
secure_topic : 200 ,
private_topic : 200 ,
deleted_topic : 404 ,
deleted_secure_topic : 404 ,
deleted_private_topic : 404 ,
nonexist : 404 ,
secure_accessible_topic : 404
}
include_examples " various scenarios " , expected
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'moderator' do
before do
sign_in ( moderator )
end
expected = {
normal_topic : 200 ,
secure_topic : 404 ,
private_topic : 404 ,
deleted_topic : 200 ,
deleted_secure_topic : 404 ,
deleted_private_topic : 404 ,
nonexist : 404 ,
secure_accessible_topic : 404
}
include_examples " various scenarios " , expected
end
context 'admin' do
before do
sign_in ( admin )
end
expected = {
normal_topic : 200 ,
secure_topic : 200 ,
private_topic : 200 ,
deleted_topic : 200 ,
deleted_secure_topic : 200 ,
deleted_private_topic : 200 ,
nonexist : 404 ,
secure_accessible_topic : 200
}
include_examples " various scenarios " , expected
end
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'with detailed error pages' do
2018-05-31 22:45:32 +08:00
before do
2019-10-08 19:15:08 +08:00
SiteSetting . detailed_404 = true
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
context 'anonymous' do
expected = {
normal_topic : 200 ,
secure_topic : 403 ,
private_topic : 403 ,
deleted_topic : 410 ,
deleted_secure_topic : 403 ,
deleted_private_topic : 403 ,
nonexist : 404 ,
secure_accessible_topic : 403
}
include_examples " various scenarios " , expected
end
context 'anonymous with login required' do
before do
SiteSetting . login_required = true
end
expected = {
normal_topic : 302 ,
secure_topic : 302 ,
private_topic : 302 ,
deleted_topic : 302 ,
deleted_secure_topic : 302 ,
deleted_private_topic : 302 ,
nonexist : 302 ,
secure_accessible_topic : 302
}
include_examples " various scenarios " , expected
end
context 'normal user' do
before do
sign_in ( user )
end
expected = {
normal_topic : 200 ,
secure_topic : 403 ,
private_topic : 403 ,
deleted_topic : 410 ,
deleted_secure_topic : 403 ,
deleted_private_topic : 403 ,
nonexist : 404 ,
secure_accessible_topic : 403
}
include_examples " various scenarios " , expected
end
context 'allowed user' do
before do
sign_in ( allowed_user )
end
expected = {
normal_topic : 200 ,
secure_topic : 200 ,
private_topic : 200 ,
deleted_topic : 410 ,
deleted_secure_topic : 410 ,
deleted_private_topic : 410 ,
nonexist : 404 ,
secure_accessible_topic : 403
}
include_examples " various scenarios " , expected
end
context 'moderator' do
before do
sign_in ( moderator )
end
expected = {
normal_topic : 200 ,
secure_topic : 403 ,
private_topic : 403 ,
deleted_topic : 200 ,
deleted_secure_topic : 403 ,
deleted_private_topic : 403 ,
nonexist : 404 ,
secure_accessible_topic : 403
}
include_examples " various scenarios " , expected
end
context 'admin' do
before do
sign_in ( admin )
end
expected = {
normal_topic : 200 ,
secure_topic : 200 ,
private_topic : 200 ,
deleted_topic : 200 ,
deleted_secure_topic : 200 ,
deleted_private_topic : 200 ,
nonexist : 404 ,
secure_accessible_topic : 200
}
include_examples " various scenarios " , expected
end
2018-05-31 22:45:32 +08:00
end
2019-10-08 19:15:08 +08:00
2018-05-31 22:45:32 +08:00
end
it 'records a view' do
expect do
get " /t/ #{ topic . slug } / #{ topic . id } .json "
end . to change ( TopicViewItem , :count ) . by ( 1 )
end
2018-11-21 08:58:47 +08:00
it 'records a view to invalid post_number' do
expect do
get " /t/ #{ topic . slug } / #{ topic . id } / #{ 256 ** 4 } " , params : {
u : user . username
}
expect ( response . status ) . to eq ( 200 )
end . to change { IncomingLink . count } . by ( 1 )
end
2018-05-31 22:45:32 +08:00
it 'records incoming links' do
expect do
get " /t/ #{ topic . slug } / #{ topic . id } " , params : {
u : user . username
}
end . to change { IncomingLink . count } . by ( 1 )
end
context 'print' do
it " doesn't renders the print view when disabled " do
SiteSetting . max_prints_per_hour_per_user = 0
get " /t/ #{ topic . slug } / #{ topic . id } /print "
expect ( response ) . to be_forbidden
end
it 'renders the print view when enabled' do
SiteSetting . max_prints_per_hour_per_user = 10
2018-06-05 12:03:49 +08:00
get " /t/ #{ topic . slug } / #{ topic . id } /print " , headers : { HTTP_USER_AGENT : " Rails Testing " }
2018-05-31 22:45:32 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
body = response . body
expect ( body ) . to have_tag ( :body , class : 'crawler' )
expect ( body ) . to_not have_tag ( :meta , with : { name : 'fragment' } )
end
it " uses the application layout when there's no param " do
SiteSetting . max_prints_per_hour_per_user = 10
get " /t/ #{ topic . slug } / #{ topic . id } " , headers : { HTTP_USER_AGENT : " Rails Testing " }
body = response . body
expect ( body ) . to have_tag ( :script , src : '/assets/application.js' )
expect ( body ) . to have_tag ( :meta , with : { name : 'fragment' } )
2018-05-31 22:45:32 +08:00
end
end
it 'records redirects' do
get " /t/ #{ topic . id } " , headers : { HTTP_REFERER : " http://twitter.com " }
get " /t/ #{ topic . slug } / #{ topic . id } " , headers : { HTTP_REFERER : nil }
link = IncomingLink . first
expect ( link . referer ) . to eq ( 'http://twitter.com' )
end
it 'tracks a visit for all html requests' do
sign_in ( user )
get " /t/ #{ topic . slug } / #{ topic . id } "
topic_user = TopicUser . where ( user : user , topic : topic ) . first
2020-03-11 05:13:17 +08:00
expect ( topic_user . last_visited_at ) . to eq_time ( topic_user . first_visited_at )
2018-05-31 22:45:32 +08:00
end
context 'consider for a promotion' do
before do
SiteSetting . tl1_requires_topics_entered = 0
SiteSetting . tl1_requires_read_posts = 0
SiteSetting . tl1_requires_time_spent_mins = 0
SiteSetting . tl1_requires_time_spent_mins = 0
end
it " reviews the user for a promotion if they're new " do
sign_in ( user )
user . update_column ( :trust_level , TrustLevel [ 0 ] )
get " /t/ #{ topic . slug } / #{ topic . id } .json "
user . reload
expect ( user . trust_level ) . to eq ( 1 )
end
end
context 'filters' do
def extract_post_stream
json = JSON . parse ( response . body )
json [ " post_stream " ] [ " posts " ] . map { | post | post [ " id " ] }
end
before do
TopicView . stubs ( :chunk_size ) . returns ( 2 )
@post_ids = topic . posts . pluck ( :id )
3 . times do
@post_ids << Fabricate ( :post , topic : topic ) . id
end
end
it 'grabs the correct set of posts' do
get " /t/ #{ topic . slug } / #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( extract_post_stream ) . to eq ( @post_ids [ 0 .. 1 ] )
get " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { page : 1 }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( extract_post_stream ) . to eq ( @post_ids [ 0 .. 1 ] )
get " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { page : 2 }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( extract_post_stream ) . to eq ( @post_ids [ 2 .. 3 ] )
post_number = topic . posts . pluck ( :post_number ) . sort [ 3 ]
get " /t/ #{ topic . slug } / #{ topic . id } / #{ post_number } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
expect ( extract_post_stream ) . to eq ( @post_ids [ - 2 .. - 1 ] )
end
end
context " when 'login required' site setting has been enabled " do
before { SiteSetting . login_required = true }
context 'and the user is logged in' do
before { sign_in ( Fabricate ( :coding_horror ) ) }
it 'shows the topic' do
get " /t/ #{ topic . slug } / #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
end
end
context 'and the user is not logged in' do
2019-11-05 22:10:23 +08:00
let ( :api_key ) { Fabricate ( :api_key , user : topic . user ) }
2018-05-31 22:45:32 +08:00
it 'redirects to the login page' do
get " /t/ #{ topic . slug } / #{ topic . id } .json "
expect ( response ) . to redirect_to login_path
end
it 'shows the topic if valid api key is provided' do
get " /t/ #{ topic . slug } / #{ topic . id } .json " , params : { api_key : api_key . key }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
topic . reload
expect ( topic . views ) . to eq ( 1 )
end
it 'returns 403 for an invalid key' do
[ :json , :html ] . each do | format |
get " /t/ #{ topic . slug } / #{ topic . id } . #{ format } " , params : { api_key : " bad " }
2019-10-08 19:15:08 +08:00
expect ( response . code . to_i ) . to eq ( 403 )
2018-05-31 22:45:32 +08:00
expect ( response . body ) . to include ( I18n . t ( " invalid_access " ) )
end
end
end
end
it " is included for unlisted topics " do
topic = Fabricate ( :topic , visible : false )
get " /t/ #{ topic . slug } / #{ topic . id } .json "
expect ( response . headers [ 'X-Robots-Tag' ] ) . to eq ( 'noindex' )
end
it " is not included for normal topics " do
topic = Fabricate ( :topic , visible : true )
get " /t/ #{ topic . slug } / #{ topic . id } .json "
expect ( response . headers [ 'X-Robots-Tag' ] ) . to eq ( nil )
end
2018-06-05 12:03:49 +08:00
it " doesn't store an incoming link when there's no referer " do
expect {
get " /t/ #{ topic . id } .json "
} . not_to change ( IncomingLink , :count )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
end
it " doesn't raise an error on a very long link " do
get " /t/ #{ topic . id } .json " , headers : { HTTP_REFERER : " http:// #{ 'a' * 2000 } .com " }
expect ( response . status ) . to eq ( 200 )
end
describe " has_escaped_fragment? " do
context " when the SiteSetting is disabled " do
it " uses the application layout even with an escaped fragment param " do
SiteSetting . enable_escaped_fragments = false
get " /t/ #{ topic . slug } / #{ topic . id } " , params : {
_escaped_fragment_ : 'true'
}
body = response . body
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( body ) . to have_tag ( :script , with : { src : '/assets/application.js' } )
expect ( body ) . to_not have_tag ( :meta , with : { name : 'fragment' } )
end
end
context " when the SiteSetting is enabled " do
before do
SiteSetting . enable_escaped_fragments = true
end
it " uses the application layout when there's no param " do
get " /t/ #{ topic . slug } / #{ topic . id } "
body = response . body
expect ( body ) . to have_tag ( :script , with : { src : '/assets/application.js' } )
expect ( body ) . to have_tag ( :meta , with : { name : 'fragment' } )
end
it " uses the crawler layout when there's an _escaped_fragment_ param " do
get " /t/ #{ topic . slug } / #{ topic . id } " , params : {
_escaped_fragment_ : true
} , headers : { HTTP_USER_AGENT : " Rails Testing " }
body = response . body
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( body ) . to have_tag ( :body , with : { class : 'crawler' } )
expect ( body ) . to_not have_tag ( :meta , with : { name : 'fragment' } )
end
end
end
describe 'clear_notifications' do
it 'correctly clears notifications if specified via cookie' do
2019-11-15 13:48:24 +08:00
set_subfolder " /eviltrout "
2018-06-05 12:03:49 +08:00
notification = Fabricate ( :notification )
sign_in ( notification . user )
cookies [ 'cn' ] = " 2828,100, #{ notification . id } "
get " /t/ #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( response . cookies [ 'cn' ] ) . to eq ( nil )
2018-06-28 23:03:36 +08:00
expect ( response . headers [ 'Set-Cookie' ] ) . to match ( / ^cn=;.*path= \/ eviltrout / )
2018-06-05 12:03:49 +08:00
notification . reload
expect ( notification . read ) . to eq ( true )
end
it 'correctly clears notifications if specified via header' do
notification = Fabricate ( :notification )
sign_in ( notification . user )
get " /t/ #{ topic . id } .json " , headers : { " Discourse-Clear-Notifications " = > " 2828,100, #{ notification . id } " }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
notification . reload
expect ( notification . read ) . to eq ( true )
end
end
describe " set_locale " do
def headers ( locale )
{ HTTP_ACCEPT_LANGUAGE : locale }
end
context " allow_user_locale disabled " do
context " accept-language header differs from default locale " do
before do
SiteSetting . allow_user_locale = false
SiteSetting . default_locale = " en "
end
context " with an anonymous user " do
it " uses the default locale " do
get " /t/ #{ topic . id } .json " , headers : headers ( " fr " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :en )
end
end
context " with a logged in user " do
it " it uses the default locale " do
user = Fabricate ( :user , locale : :fr )
sign_in ( user )
get " /t/ #{ topic . id } .json " , headers : headers ( " fr " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :en )
end
end
end
end
context " set_locale_from_accept_language_header enabled " do
context " accept-language header differs from default locale " do
before do
SiteSetting . allow_user_locale = true
SiteSetting . set_locale_from_accept_language_header = true
SiteSetting . default_locale = " en "
end
context " with an anonymous user " do
it " uses the locale from the headers " do
get " /t/ #{ topic . id } .json " , headers : headers ( " fr " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :fr )
end
end
context " with a logged in user " do
it " uses the user's preferred locale " do
user = Fabricate ( :user , locale : :fr )
sign_in ( user )
get " /t/ #{ topic . id } .json " , headers : headers ( " fr " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :fr )
end
end
end
context " the preferred locale includes a region " do
it " returns the locale and region separated by an underscore " do
SiteSetting . allow_user_locale = true
SiteSetting . set_locale_from_accept_language_header = true
SiteSetting . default_locale = " en "
get " /t/ #{ topic . id } .json " , headers : headers ( " zh-CN " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :zh_CN )
end
end
context 'accept-language header is not set' do
it 'uses the site default locale' do
SiteSetting . allow_user_locale = true
SiteSetting . default_locale = 'en'
get " /t/ #{ topic . id } .json " , headers : headers ( " " )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( I18n . locale ) . to eq ( :en )
end
end
end
end
describe " read only header " do
it " returns no read only header by default " do
get " /t/ #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( response . headers [ 'Discourse-Readonly' ] ) . to eq ( nil )
end
it " returns a readonly header if the site is read only " do
2019-06-21 22:08:57 +08:00
Discourse . received_postgres_readonly!
2018-06-05 12:03:49 +08:00
get " /t/ #{ topic . id } .json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-06-05 12:03:49 +08:00
expect ( response . headers [ 'Discourse-Readonly' ] ) . to eq ( 'true' )
end
end
2018-10-17 16:19:32 +08:00
describe " image only topic " do
it " uses image alt tag for meta description " do
post = Fabricate ( :post , raw : " ![image_description|690x405](upload://sdtr5O5xaxf0iEOxICxL36YRj86.png) " )
get post . topic . url
body = response . body
expect ( body ) . to have_tag ( :meta , with : { name : 'description' , content : '[image_description]' } )
end
end
2018-05-31 22:45:32 +08:00
end
2018-06-28 14:54:54 +08:00
describe '#post_ids' do
let ( :post ) { Fabricate ( :post ) }
let ( :topic ) { post . topic }
before do
TopicView . stubs ( :chunk_size ) . returns ( 1 )
end
it 'returns the right post ids' do
post2 = Fabricate ( :post , topic : topic )
post3 = Fabricate ( :post , topic : topic )
get " /t/ #{ topic . id } /post_ids.json " , params : {
post_number : post . post_number
}
expect ( response . status ) . to eq ( 200 )
body = JSON . parse ( response . body )
expect ( body [ " post_ids " ] ) . to eq ( [ post2 . id , post3 . id ] )
end
describe 'filtering by post number with filters' do
describe 'username filters' do
let ( :post ) { Fabricate ( :post , user : user ) }
let! ( :post2 ) { Fabricate ( :post , topic : topic , user : user ) }
let! ( :post3 ) { Fabricate ( :post , topic : topic ) }
it 'should return the right posts' do
get " /t/ #{ topic . id } /post_ids.json " , params : {
post_number : post . post_number ,
username_filters : post2 . user . username
}
expect ( response . status ) . to eq ( 200 )
body = JSON . parse ( response . body )
expect ( body [ " post_ids " ] ) . to eq ( [ post2 . id ] )
end
end
describe 'summary filter' do
let! ( :post2 ) { Fabricate ( :post , topic : topic , percent_rank : 0 . 2 ) }
let! ( :post3 ) { Fabricate ( :post , topic : topic ) }
it 'should return the right posts' do
get " /t/ #{ topic . id } /post_ids.json " , params : {
post_number : post . post_number ,
filter : 'summary'
}
expect ( response . status ) . to eq ( 200 )
body = JSON . parse ( response . body )
expect ( body [ " post_ids " ] ) . to eq ( [ post2 . id ] )
end
end
end
end
2018-05-31 22:45:32 +08:00
describe '#posts' do
2018-07-11 15:41:26 +08:00
let ( :post ) { Fabricate ( :post ) }
let ( :topic ) { post . topic }
2018-05-31 22:45:32 +08:00
2020-03-11 05:13:17 +08:00
after do
Discourse . redis . flushall
end
2018-07-11 15:41:26 +08:00
it 'returns first post of the topic' do
2019-02-22 07:37:18 +08:00
# we need one for suggested
create_post
2018-05-31 22:45:32 +08:00
get " /t/ #{ topic . id } /posts.json "
2018-07-11 15:41:26 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-07-11 15:41:26 +08:00
body = JSON . parse ( response . body )
expect ( body [ " post_stream " ] [ " posts " ] . first [ " id " ] ) . to eq ( post . id )
2019-02-22 07:37:18 +08:00
expect ( body [ " suggested_topics " ] ) . to eq ( nil )
get " /t/ #{ topic . id } /posts.json?include_suggested=true "
body = JSON . parse ( response . body )
expect ( body [ " suggested_topics " ] ) . not_to eq ( nil )
2018-07-11 15:41:26 +08:00
end
describe 'filtering by post number with filters' do
describe 'username filters' do
2019-05-06 17:44:15 +08:00
let! ( :post2 ) { Fabricate ( :post , topic : topic , user : user ) }
2018-07-11 15:41:26 +08:00
let! ( :post3 ) { Fabricate ( :post , topic : topic ) }
it 'should return the right posts' do
TopicView . stubs ( :chunk_size ) . returns ( 2 )
get " /t/ #{ topic . id } /posts.json " , params : {
post_number : post . post_number ,
username_filters : post2 . user . username ,
asc : true
}
expect ( response . status ) . to eq ( 200 )
body = JSON . parse ( response . body )
expect ( body [ " post_stream " ] [ " posts " ] . first [ " id " ] ) . to eq ( post2 . id )
end
end
describe 'summary filter' do
let! ( :post2 ) { Fabricate ( :post , topic : topic , percent_rank : 0 . 2 ) }
let! ( :post3 ) { Fabricate ( :post , topic : topic ) }
it 'should return the right posts' do
TopicView . stubs ( :chunk_size ) . returns ( 2 )
get " /t/ #{ topic . id } /posts.json " , params : {
post_number : post . post_number ,
filter : 'summary' ,
asc : true
}
expect ( response . status ) . to eq ( 200 )
body = JSON . parse ( response . body )
expect ( body [ " post_stream " ] [ " posts " ] . first [ " id " ] ) . to eq ( post2 . id )
end
end
2018-05-31 22:45:32 +08:00
end
end
describe '#feed' do
let ( :topic ) { Fabricate ( :post ) . topic }
it 'renders rss of the topic' do
get " /t/foo/ #{ topic . id } .rss "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2019-09-12 08:41:50 +08:00
expect ( response . media_type ) . to eq ( 'application/rss+xml' )
2018-05-31 22:45:32 +08:00
end
2018-08-28 06:05:08 +08:00
it 'renders rss of the topic correctly with subfolder' do
2019-11-15 13:48:24 +08:00
set_subfolder " /forum "
2018-08-28 06:05:08 +08:00
get " /t/foo/ #{ topic . id } .rss "
expect ( response . status ) . to eq ( 200 )
expect ( response . body ) . to_not include ( " /forum/forum " )
expect ( response . body ) . to include ( " http://test.localhost/forum/t/ #{ topic . slug } " )
end
2018-05-31 22:45:32 +08:00
end
describe '#invite_group' do
let ( :admins ) { Group [ :admins ] }
before do
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2018-05-31 22:45:32 +08:00
admins . messageable_level = Group :: ALIAS_LEVELS [ :everyone ]
admins . save!
end
it " disallows inviting a group to a topic " do
topic = Fabricate ( :topic )
post " /t/ #{ topic . id } /invite-group.json " , params : {
group : 'admins'
}
expect ( response . status ) . to eq ( 422 )
end
it " allows inviting a group to a PM " do
topic = Fabricate ( :private_message_topic )
post " /t/ #{ topic . id } /invite-group.json " , params : {
group : 'admins'
}
expect ( response . status ) . to eq ( 200 )
expect ( topic . allowed_groups . first . id ) . to eq ( admins . id )
end
end
describe '#make_banner' do
it 'needs you to be a staff member' do
2019-05-06 19:19:50 +08:00
topic = Fabricate ( :topic , user : sign_in ( trust_level_4 ) )
2019-04-02 15:08:15 +08:00
put " /t/ #{ topic . id } /make-banner.json "
2018-05-31 22:45:32 +08:00
expect ( response ) . to be_forbidden
end
describe 'when logged in' do
it " changes the topic archetype to 'banner' " do
2019-05-06 18:00:22 +08:00
topic = Fabricate ( :topic , user : sign_in ( admin ) )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /make-banner.json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
topic . reload
expect ( topic . archetype ) . to eq ( Archetype . banner )
end
end
end
describe '#remove_banner' do
it 'needs you to be a staff member' do
2019-05-06 19:19:50 +08:00
topic = Fabricate ( :topic , user : sign_in ( trust_level_4 ) , archetype : Archetype . banner )
2019-04-02 15:08:15 +08:00
put " /t/ #{ topic . id } /remove-banner.json "
2018-05-31 22:45:32 +08:00
expect ( response ) . to be_forbidden
end
describe 'when logged in' do
it " resets the topic archetype " do
2019-05-06 18:00:22 +08:00
topic = Fabricate ( :topic , user : sign_in ( admin ) , archetype : Archetype . banner )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /remove-banner.json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
topic . reload
expect ( topic . archetype ) . to eq ( Archetype . default )
end
end
end
describe '#remove_allowed_user' do
it 'admin can be removed from a pm' do
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2018-05-31 22:45:32 +08:00
pm = create_post ( user : user , archetype : 'private_message' , target_usernames : [ user . username , admin . username ] )
put " /t/ #{ pm . topic_id } /remove-allowed-user.json " , params : {
username : admin . username
}
expect ( response . status ) . to eq ( 200 )
expect ( TopicAllowedUser . where ( topic_id : pm . topic_id , user_id : admin . id ) . first ) . to eq ( nil )
end
end
describe '#bulk' do
it 'needs you to be logged in' do
put " /topics/bulk.json "
expect ( response . status ) . to eq ( 403 )
end
describe " when logged in " do
2019-05-06 17:44:15 +08:00
before { sign_in ( user ) }
2018-05-31 22:45:32 +08:00
let ( :operation ) { { type : 'change_category' , category_id : '1' } }
let ( :topic_ids ) { [ 1 , 2 , 3 ] }
it " requires a list of topic_ids or filter " do
put " /topics/bulk.json " , params : { operation : operation }
expect ( response . status ) . to eq ( 400 )
end
it " requires an operation param " do
put " /topics/bulk.json " , params : { topic_ids : topic_ids }
expect ( response . status ) . to eq ( 400 )
end
it " requires a type field for the operation param " do
put " /topics/bulk.json " , params : { topic_ids : topic_ids , operation : { } }
expect ( response . status ) . to eq ( 400 )
end
2019-06-27 11:26:07 +08:00
it " can mark sub-categories unread " do
2019-08-06 18:26:54 +08:00
category = Fabricate ( :category )
sub = Fabricate ( :category , parent_category_id : category . id )
2019-06-27 11:26:07 +08:00
topic . update! ( category_id : sub . id )
post1 = create_post ( user : user , topic_id : topic . id )
create_post ( topic_id : topic . id )
put " /topics/bulk.json " , params : {
category_id : category . id ,
include_subcategories : true ,
filter : 'unread' ,
operation : { type : 'dismiss_posts' }
}
expect ( response . status ) . to eq ( 200 )
expect ( TopicUser . get ( post1 . topic , post1 . user ) . last_read_post_number ) . to eq ( 2 )
end
2018-05-31 22:45:32 +08:00
it " can find unread " do
# mark all unread muted
put " /topics/bulk.json " , params : {
filter : 'unread' , operation : { type : :change_notification_level , notification_level_id : 0 }
}
expect ( response . status ) . to eq ( 200 )
end
it " delegates work to `TopicsBulkAction` " do
topics_bulk_action = mock
TopicsBulkAction . expects ( :new ) . with ( user , topic_ids , operation , group : nil ) . returns ( topics_bulk_action )
topics_bulk_action . expects ( :perform! )
put " /topics/bulk.json " , params : {
topic_ids : topic_ids , operation : operation
}
end
end
end
describe '#remove_bookmarks' do
it " should remove bookmarks properly from non first post " do
bookmark = PostActionType . types [ :bookmark ]
2019-05-06 17:44:15 +08:00
sign_in ( user )
2018-05-31 22:45:32 +08:00
post = create_post
post2 = create_post ( topic_id : post . topic_id )
2019-01-04 01:03:01 +08:00
PostActionCreator . new ( user , post2 , bookmark ) . perform
2018-05-31 22:45:32 +08:00
put " /t/ #{ post . topic_id } /bookmark.json "
expect ( PostAction . where ( user_id : user . id , post_action_type : bookmark ) . count ) . to eq ( 2 )
put " /t/ #{ post . topic_id } /remove_bookmarks.json "
expect ( PostAction . where ( user_id : user . id , post_action_type : bookmark ) . count ) . to eq ( 0 )
end
it " should disallow bookmarks on posts you have no access to " do
sign_in ( Fabricate ( :user ) )
pm = create_post ( user : user , archetype : 'private_message' , target_usernames : [ user . username ] )
put " /t/ #{ pm . topic_id } /bookmark.json "
expect ( response ) . to be_forbidden
end
2020-02-13 14:26:02 +08:00
context " when SiteSetting.enable_bookmarks_with_reminders is true " do
before do
SiteSetting . enable_bookmarks_with_reminders = true
end
it " deletes all the bookmarks for the user in the topic " do
sign_in ( user )
post = create_post
Fabricate ( :bookmark , post : post , topic : post . topic , user : user )
put " /t/ #{ post . topic_id } /remove_bookmarks.json "
expect ( Bookmark . where ( user : user , topic : topic ) . count ) . to eq ( 0 )
end
end
end
describe " # bookmark " do
before do
sign_in ( user )
end
it " should create a new post action for the bookmark on the first post of the topic " do
post = create_post
post2 = create_post ( topic_id : post . topic_id )
put " /t/ #{ post . topic_id } /bookmark.json "
expect ( PostAction . find_by ( user_id : user . id , post_action_type : PostActionType . types [ :bookmark ] ) . post_id ) . to eq ( post . id )
end
it " errors if the topic is already bookmarked for the user " do
post = create_post
PostActionCreator . new ( user , post , PostActionType . types [ :bookmark ] ) . perform
put " /t/ #{ post . topic_id } /bookmark.json "
expect ( response ) . to be_forbidden
end
context " when SiteSetting.enable_bookmarks_with_reminders is true " do
before do
SiteSetting . enable_bookmarks_with_reminders = true
end
it " should create a new bookmark on the first post of the topic " do
post = create_post
post2 = create_post ( topic_id : post . topic_id )
put " /t/ #{ post . topic_id } /bookmark.json "
2020-03-13 11:33:57 +08:00
expect ( response . status ) . to eq ( 200 )
2020-02-13 14:26:02 +08:00
bookmarks_for_topic = Bookmark . where ( topic : post . topic , user : user )
expect ( bookmarks_for_topic . count ) . to eq ( 1 )
expect ( bookmarks_for_topic . first . post_id ) . to eq ( post . id )
end
it " errors if the topic is already bookmarked for the user " do
post = create_post
Bookmark . create ( post : post , topic : post . topic , user : user )
put " /t/ #{ post . topic_id } /bookmark.json "
2020-03-12 08:16:00 +08:00
expect ( response . status ) . to eq ( 400 )
2020-02-13 14:26:02 +08:00
end
end
2018-05-31 22:45:32 +08:00
end
describe '#reset_new' do
it 'needs you to be logged in' do
put " /topics/reset-new.json "
expect ( response . status ) . to eq ( 403 )
end
it " updates the `new_since` date " do
2019-05-06 17:44:15 +08:00
sign_in ( user )
2018-05-31 22:45:32 +08:00
old_date = 2 . years . ago
user . user_stat . update_column ( :new_since , old_date )
2019-11-25 03:17:31 +08:00
TopicTrackingState . expects ( :publish_dismiss_new ) . with ( user . id )
2018-05-31 22:45:32 +08:00
put " /topics/reset-new.json "
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
user . reload
expect ( user . user_stat . new_since . to_date ) . not_to eq ( old_date . to_date )
end
2019-11-14 08:16:13 +08:00
context 'category' do
fab! ( :category ) { Fabricate ( :category ) }
fab! ( :subcategory ) { Fabricate ( :category , parent_category_id : category . id ) }
it 'updates last_seen_at for main category' do
sign_in ( user )
category_user = CategoryUser . create! ( category_id : category . id , user_id : user . id )
subcategory_user = CategoryUser . create! ( category_id : subcategory . id , user_id : user . id )
2019-11-25 03:17:31 +08:00
TopicTrackingState . expects ( :publish_dismiss_new ) . with ( user . id , category . id . to_s )
2019-11-14 08:16:13 +08:00
put " /topics/reset-new.json?category_id= #{ category . id } "
expect ( category_user . reload . last_seen_at ) . not_to be_nil
expect ( subcategory_user . reload . last_seen_at ) . to be_nil
end
it 'updates last_seen_at for main category and subcategories' do
sign_in ( user )
category_user = CategoryUser . create! ( category_id : category . id , user_id : user . id )
subcategory_user = CategoryUser . create! ( category_id : subcategory . id , user_id : user . id )
put " /topics/reset-new.json?category_id= #{ category . id } &include_subcategories=true "
expect ( category_user . reload . last_seen_at ) . not_to be_nil
expect ( subcategory_user . reload . last_seen_at ) . not_to be_nil
end
end
2018-05-31 22:45:32 +08:00
end
describe '#feature_stats' do
it " works " do
get " /topics/feature_stats.json " , params : { category_id : 1 }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
json = JSON . parse ( response . body )
expect ( json [ " pinned_in_category_count " ] ) . to eq ( 0 )
expect ( json [ " pinned_globally_count " ] ) . to eq ( 0 )
expect ( json [ " banner_count " ] ) . to eq ( 0 )
end
it " allows unlisted banner topic " do
Fabricate ( :topic , category_id : 1 , archetype : Archetype . banner , visible : false )
get " /topics/feature_stats.json " , params : { category_id : 1 }
json = JSON . parse ( response . body )
expect ( json [ " banner_count " ] ) . to eq ( 1 )
end
end
describe '#excerpts' do
it " can correctly get excerpts " do
first_post = create_post ( raw : 'This is the first post :)' , title : 'This is a test title I am making yay' )
second_post = create_post ( raw : 'This is second post' , topic : first_post . topic )
random_post = Fabricate ( :post )
get " /t/ #{ first_post . topic_id } /excerpts.json " , params : {
post_ids : [ first_post . id , second_post . id , random_post . id ]
}
json = JSON . parse ( response . body )
json . sort! { | a , b | a [ " post_id " ] < = > b [ " post_id " ] }
# no random post
expect ( json . length ) . to eq ( 2 )
# keep emoji images
expect ( json [ 0 ] [ " excerpt " ] ) . to match ( / emoji / )
expect ( json [ 0 ] [ " excerpt " ] ) . to match ( / first post / )
expect ( json [ 0 ] [ " username " ] ) . to eq ( first_post . user . username )
expect ( json [ 0 ] [ " post_id " ] ) . to eq ( first_post . id )
expect ( json [ 1 ] [ " excerpt " ] ) . to match ( / second post / )
end
end
describe '#convert_topic' do
it 'needs you to be logged in' do
put " /t/111/convert-topic/private.json "
expect ( response . status ) . to eq ( 403 )
end
describe 'converting public topic to private message' do
let ( :topic ) { Fabricate ( :topic , user : user ) }
2019-04-16 15:47:16 +08:00
let! ( :post ) { Fabricate ( :post , topic : topic ) }
2018-05-31 22:45:32 +08:00
it " raises an error when the user doesn't have permission to convert topic " do
2019-05-06 17:44:15 +08:00
sign_in ( user )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /convert-topic/private.json "
expect ( response ) . to be_forbidden
end
context " success " do
it " returns success " do
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /convert-topic/private.json "
topic . reload
expect ( topic . archetype ) . to eq ( Archetype . private_message )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
end
end
describe 'converting private message to public topic' do
let ( :topic ) { Fabricate ( :private_message_topic , user : user ) }
2019-04-16 15:47:16 +08:00
let! ( :post ) { Fabricate ( :post , topic : topic ) }
2018-05-31 22:45:32 +08:00
it " raises an error when the user doesn't have permission to convert topic " do
2019-05-06 17:44:15 +08:00
sign_in ( user )
2018-05-31 22:45:32 +08:00
put " /t/ #{ topic . id } /convert-topic/public.json "
expect ( response ) . to be_forbidden
end
context " success " do
2019-07-19 23:52:50 +08:00
fab! ( :category ) { Fabricate ( :category ) }
2018-05-31 22:45:32 +08:00
it " returns success " do
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2019-07-19 23:52:50 +08:00
put " /t/ #{ topic . id } /convert-topic/public.json?category_id= #{ category . id } "
2018-05-31 22:45:32 +08:00
topic . reload
expect ( topic . archetype ) . to eq ( Archetype . default )
2019-07-19 23:52:50 +08:00
expect ( topic . category_id ) . to eq ( category . id )
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-05-31 22:45:32 +08:00
result = :: JSON . parse ( response . body )
expect ( result [ 'success' ] ) . to eq ( true )
expect ( result [ 'url' ] ) . to be_present
end
end
end
2017-09-28 11:04:17 +08:00
end
2017-09-04 16:36:02 +08:00
describe '#timings' do
let ( :post_1 ) { Fabricate ( :post , topic : topic ) }
it 'should record the timing' do
sign_in ( user )
2017-08-31 12:06:56 +08:00
post " /topics/timings.json " , params : {
2017-09-04 16:36:02 +08:00
topic_id : topic . id ,
topic_time : 5 ,
timings : { post_1 . post_number = > 2 }
2017-08-31 12:06:56 +08:00
}
2017-09-04 16:36:02 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2017-09-04 16:36:02 +08:00
post_timing = PostTiming . first
expect ( post_timing . topic ) . to eq ( topic )
expect ( post_timing . user ) . to eq ( user )
expect ( post_timing . msecs ) . to eq ( 2 )
end
end
2017-08-24 11:01:11 +08:00
describe '#timer' do
context 'when a user is not logged in' do
it 'should return the right response' do
2018-01-12 11:15:10 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
time : '24' ,
status_type : TopicTimer . types [ 1 ]
}
expect ( response . status ) . to eq ( 403 )
2017-08-24 11:01:11 +08:00
end
end
context 'when does not have permission' do
it 'should return the right response' do
sign_in ( user )
2017-08-31 12:06:56 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
2017-08-24 11:01:11 +08:00
time : '24' ,
status_type : TopicTimer . types [ 1 ]
2017-08-31 12:06:56 +08:00
}
2017-08-24 11:01:11 +08:00
expect ( response . status ) . to eq ( 403 )
expect ( JSON . parse ( response . body ) [ " error_type " ] ) . to eq ( 'invalid_access' )
end
end
context 'when logged in as an admin' do
before do
2020-03-11 05:13:17 +08:00
freeze_time
2017-08-24 11:01:11 +08:00
sign_in ( admin )
end
it 'should be able to create a topic status update' do
2017-08-31 12:06:56 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
2017-08-24 11:01:11 +08:00
time : 24 ,
status_type : TopicTimer . types [ 1 ]
2017-08-31 12:06:56 +08:00
}
2017-08-24 11:01:11 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2017-08-24 11:01:11 +08:00
topic_status_update = TopicTimer . last
expect ( topic_status_update . topic ) . to eq ( topic )
2020-03-11 05:13:17 +08:00
expect ( topic_status_update . execute_at ) . to eq_time ( 24 . hours . from_now )
2017-08-24 11:01:11 +08:00
json = JSON . parse ( response . body )
expect ( DateTime . parse ( json [ 'execute_at' ] ) )
2020-03-11 05:13:17 +08:00
. to eq_time ( DateTime . parse ( topic_status_update . execute_at . to_s ) )
2017-08-24 11:01:11 +08:00
expect ( json [ 'duration' ] ) . to eq ( topic_status_update . duration )
expect ( json [ 'closed' ] ) . to eq ( topic . reload . closed )
end
it 'should be able to delete a topic status update' do
Fabricate ( :topic_timer , topic : topic )
2017-08-31 12:06:56 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
2017-08-24 11:01:11 +08:00
time : nil ,
status_type : TopicTimer . types [ 1 ]
2017-08-31 12:06:56 +08:00
}
2017-08-24 11:01:11 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2017-08-24 11:01:11 +08:00
expect ( topic . reload . public_topic_timer ) . to eq ( nil )
json = JSON . parse ( response . body )
expect ( json [ 'execute_at' ] ) . to eq ( nil )
expect ( json [ 'duration' ] ) . to eq ( nil )
expect ( json [ 'closed' ] ) . to eq ( topic . closed )
end
2020-03-19 23:36:31 +08:00
it 'should be able to create a topic status update with duration' do
post " /t/ #{ topic . id } /timer.json " , params : {
duration : 5 ,
status_type : TopicTimer . types [ 7 ]
}
expect ( response . status ) . to eq ( 200 )
topic_status_update = TopicTimer . last
expect ( topic_status_update . topic ) . to eq ( topic )
expect ( topic_status_update . execute_at ) . to eq_time ( 5 . days . from_now )
expect ( topic_status_update . duration ) . to eq ( 5 )
json = JSON . parse ( response . body )
expect ( DateTime . parse ( json [ 'execute_at' ] ) )
. to eq_time ( DateTime . parse ( topic_status_update . execute_at . to_s ) )
expect ( json [ 'duration' ] ) . to eq ( topic_status_update . duration )
end
2017-08-24 11:01:11 +08:00
describe 'publishing topic to category in the future' do
it 'should be able to create the topic status update' do
2017-08-31 12:06:56 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
2017-08-24 11:01:11 +08:00
time : 24 ,
status_type : TopicTimer . types [ 3 ] ,
category_id : topic . category_id
2017-08-31 12:06:56 +08:00
}
2017-08-24 11:01:11 +08:00
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2017-08-24 11:01:11 +08:00
topic_status_update = TopicTimer . last
expect ( topic_status_update . topic ) . to eq ( topic )
2020-03-11 05:13:17 +08:00
expect ( topic_status_update . execute_at ) . to eq_time ( 24 . hours . from_now )
2017-08-24 11:01:11 +08:00
expect ( topic_status_update . status_type )
. to eq ( TopicTimer . types [ :publish_to_category ] )
json = JSON . parse ( response . body )
expect ( json [ 'category_id' ] ) . to eq ( topic . category_id )
end
end
describe 'invalid status type' do
it 'should raise the right error' do
2018-01-12 11:15:10 +08:00
post " /t/ #{ topic . id } /timer.json " , params : {
time : 10 ,
status_type : 'something'
}
expect ( response . status ) . to eq ( 400 )
expect ( response . body ) . to include ( 'status_type' )
2017-08-24 11:01:11 +08:00
end
end
end
end
2017-12-14 10:53:21 +08:00
2018-02-26 10:42:06 +08:00
describe '#invite' do
describe 'when not logged in' do
it " should return the right response " do
post " /t/ #{ topic . id } /invite.json " , params : {
email : 'jake@adventuretime.ooo'
}
expect ( response . status ) . to eq ( 403 )
end
end
describe 'when logged in' do
before do
sign_in ( user )
end
describe 'as a valid user' do
let ( :topic ) { Fabricate ( :topic , user : user ) }
it 'should return the right response' do
user . update! ( trust_level : TrustLevel [ 2 ] )
expect do
post " /t/ #{ topic . id } /invite.json " , params : {
email : 'someguy@email.com'
}
end . to change { Invite . where ( invited_by_id : user . id ) . count } . by ( 1 )
expect ( response . status ) . to eq ( 200 )
end
end
describe 'when user is a group manager' do
let ( :group ) { Fabricate ( :group ) . tap { | g | g . add_owner ( user ) } }
let ( :private_category ) { Fabricate ( :private_category , group : group ) }
let ( :group_private_topic ) do
Fabricate ( :topic , category : private_category , user : user )
end
let ( :recipient ) { 'jake@adventuretime.ooo' }
it " should attach group to the invite " do
post " /t/ #{ group_private_topic . id } /invite.json " , params : {
2018-12-05 23:43:07 +08:00
user : recipient ,
group_ids : " #{ group . id } ,123 "
2018-02-26 10:42:06 +08:00
}
expect ( response . status ) . to eq ( 200 )
expect ( Invite . find_by ( email : recipient ) . groups ) . to eq ( [ group ] )
end
2018-12-05 23:43:07 +08:00
describe 'when group is available to automatic groups only' do
before do
group . update! ( automatic : true )
end
it 'should return the right response' do
post " /t/ #{ group_private_topic . id } /invite.json " , params : {
2019-05-06 17:44:15 +08:00
user : user
2018-12-05 23:43:07 +08:00
}
expect ( response . status ) . to eq ( 403 )
end
end
describe 'when user is not part of the required group' do
it 'should return the right response' do
post " /t/ #{ group_private_topic . id } /invite.json " , params : {
2019-05-06 17:44:15 +08:00
user : user
2018-12-05 23:43:07 +08:00
}
expect ( response . status ) . to eq ( 422 )
response_body = JSON . parse ( response . body )
expect ( response_body [ " errors " ] ) . to eq ( [
I18n . t ( " topic_invite.failed_to_invite " ,
group_names : group . name
)
] )
end
end
2018-02-26 10:42:06 +08:00
end
describe 'when topic id is invalid' do
it 'should return the right response' do
post " /t/999/invite.json " , params : {
2019-05-06 17:44:15 +08:00
email : user . email
2018-02-26 10:42:06 +08:00
}
expect ( response . status ) . to eq ( 400 )
end
end
it 'requires an email parameter' do
post " /t/ #{ topic . id } /invite.json "
expect ( response . status ) . to eq ( 400 )
end
2018-08-23 12:36:49 +08:00
describe " when PM has reached maximum allowed numbers of recipients " do
2019-05-07 11:12:20 +08:00
fab! ( :user2 ) { Fabricate ( :user ) }
2018-08-23 12:36:49 +08:00
let ( :pm ) { Fabricate ( :private_message_topic , user : user ) }
let ( :moderator_pm ) { Fabricate ( :private_message_topic , user : moderator ) }
before do
SiteSetting . max_allowed_message_recipients = 2
end
it " doesn't allow normal users to invite " do
post " /t/ #{ pm . id } /invite.json " , params : {
user : user2 . username
}
expect ( response . status ) . to eq ( 422 )
expect ( JSON . parse ( response . body ) [ " errors " ] ) . to contain_exactly (
I18n . t ( " pm_reached_recipients_limit " , recipients_limit : SiteSetting . max_allowed_message_recipients )
)
end
it " allows staff to bypass limits " do
sign_in ( moderator )
post " /t/ #{ moderator_pm . id } /invite.json " , params : {
user : user2 . username
}
expect ( response . status ) . to eq ( 200 )
expect ( moderator_pm . reload . topic_allowed_users . count ) . to eq ( 3 )
end
end
2018-02-26 10:42:06 +08:00
describe 'when user does not have permission to invite to the topic' do
let ( :topic ) { Fabricate ( :private_message_topic ) }
it " should return the right response " do
post " /t/ #{ topic . id } /invite.json " , params : {
user : user . username
}
expect ( response . status ) . to eq ( 403 )
end
end
end
describe " when inviting a group to a topic " do
let ( :group ) { Fabricate ( :group ) }
before do
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2018-02-26 10:42:06 +08:00
end
it " should work correctly " do
email = 'hiro@from.heros'
post " /t/ #{ topic . id } /invite.json " , params : {
email : email , group_ids : group . id
}
expect ( response . status ) . to eq ( 200 )
groups = Invite . find_by ( email : email ) . groups
expect ( groups . count ) . to eq ( 1 )
expect ( groups . first . id ) . to eq ( group . id )
end
end
end
2017-12-14 10:53:21 +08:00
describe 'invite_group' do
let ( :admins ) { Group [ :admins ] }
let ( :pm ) { Fabricate ( :private_message_topic ) }
def invite_group ( topic , expected_status )
post " /t/ #{ topic . id } /invite-group.json " , params : { group : admins . name }
expect ( response . status ) . to eq ( expected_status )
end
before do
admins . update! ( messageable_level : Group :: ALIAS_LEVELS [ :everyone ] )
end
describe 'as an anon user' do
it 'should be forbidden' do
invite_group ( pm , 403 )
end
end
describe 'as a normal user' do
let! ( :user ) { sign_in ( Fabricate ( :user ) ) }
describe 'when user does not have permission to view the topic' do
it 'should be forbidden' do
invite_group ( pm , 403 )
end
end
describe 'when user has permission to view the topic' do
before do
pm . allowed_users << user
end
it 'should allow user to invite group to topic' do
invite_group ( pm , 200 )
expect ( pm . allowed_groups . first . id ) . to eq ( admins . id )
end
end
end
describe 'as an admin user' do
2019-05-06 18:00:22 +08:00
before do
sign_in ( admin )
end
2017-12-14 10:53:21 +08:00
it " disallows inviting a group to a topic " do
topic = Fabricate ( :topic )
invite_group ( topic , 422 )
end
it " allows inviting a group to a PM " do
invite_group ( pm , 200 )
expect ( pm . allowed_groups . first . id ) . to eq ( admins . id )
end
end
2018-08-23 12:36:49 +08:00
context " when PM has reached maximum allowed numbers of recipients " do
let ( :group ) { Fabricate ( :group , messageable_level : 99 ) }
let ( :pm ) { Fabricate ( :private_message_topic , user : user ) }
let ( :moderator_pm ) { Fabricate ( :private_message_topic , user : moderator ) }
before do
SiteSetting . max_allowed_message_recipients = 2
end
it " doesn't allow normal users to invite " do
post " /t/ #{ pm . id } /invite-group.json " , params : {
group : group . name
}
expect ( response . status ) . to eq ( 422 )
expect ( JSON . parse ( response . body ) [ " errors " ] ) . to contain_exactly (
I18n . t ( " pm_reached_recipients_limit " , recipients_limit : SiteSetting . max_allowed_message_recipients )
)
end
it " allows staff to bypass limits " do
sign_in ( moderator )
post " /t/ #{ moderator_pm . id } /invite-group.json " , params : {
group : group . name
}
expect ( response . status ) . to eq ( 200 )
expect ( moderator_pm . reload . topic_allowed_users . count + moderator_pm . topic_allowed_groups . count ) . to eq ( 3 )
end
end
2017-12-14 10:53:21 +08:00
end
2018-03-14 03:59:12 +08:00
describe 'shared drafts' do
let ( :shared_drafts_category ) { Fabricate ( :category ) }
before do
SiteSetting . shared_drafts_category = shared_drafts_category . id
end
2018-03-23 23:12:22 +08:00
describe " # update_shared_draft " do
let ( :other_cat ) { Fabricate ( :category ) }
2018-03-23 23:33:02 +08:00
let ( :category ) { Fabricate ( :category ) }
2018-03-23 23:12:22 +08:00
let ( :topic ) { Fabricate ( :topic , category : shared_drafts_category , visible : false ) }
context " anonymous " do
it " doesn't allow staff to update the shared draft " do
put " /t/ #{ topic . id } /shared-draft.json " , params : { category_id : other_cat . id }
expect ( response . code . to_i ) . to eq ( 403 )
end
end
context " as a moderator " do
before do
sign_in ( moderator )
end
2018-03-23 23:33:02 +08:00
context " with a shared draft " do
let! ( :shared_draft ) { Fabricate ( :shared_draft , topic : topic , category : category ) }
it " allows staff to update the category id " do
put " /t/ #{ topic . id } /shared-draft.json " , params : { category_id : other_cat . id }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-03-23 23:33:02 +08:00
topic . reload
expect ( topic . shared_draft . category_id ) . to eq ( other_cat . id )
end
end
context " without a shared draft " do
it " allows staff to update the category id " do
put " /t/ #{ topic . id } /shared-draft.json " , params : { category_id : other_cat . id }
2018-06-07 16:11:09 +08:00
expect ( response . status ) . to eq ( 200 )
2018-03-23 23:33:02 +08:00
topic . reload
expect ( topic . shared_draft . category_id ) . to eq ( other_cat . id )
end
2018-03-23 23:12:22 +08:00
end
end
end
2018-03-14 03:59:12 +08:00
describe " # publish " do
let ( :category ) { Fabricate ( :category ) }
let ( :topic ) { Fabricate ( :topic , category : shared_drafts_category , visible : false ) }
2019-04-16 15:47:16 +08:00
let! ( :post ) { Fabricate ( :post , topic : topic ) }
2018-03-14 03:59:12 +08:00
it " fails for anonymous users " do
2018-03-21 08:33:06 +08:00
put " /t/ #{ topic . id } /publish.json " , params : { destination_category_id : category . id }
expect ( response . status ) . to eq ( 403 )
2018-03-14 03:59:12 +08:00
end
it " fails as a regular user " do
2019-05-06 17:44:15 +08:00
sign_in ( user )
2018-03-21 08:33:06 +08:00
put " /t/ #{ topic . id } /publish.json " , params : { destination_category_id : category . id }
expect ( response . status ) . to eq ( 403 )
2018-03-14 03:59:12 +08:00
end
context " as staff " do
before do
sign_in ( moderator )
end
it " will publish the topic " do
put " /t/ #{ topic . id } /publish.json " , params : { destination_category_id : category . id }
2018-03-21 08:33:06 +08:00
expect ( response . status ) . to eq ( 200 )
2018-03-14 03:59:12 +08:00
json = :: JSON . parse ( response . body ) [ 'basic_topic' ]
result = Topic . find ( json [ 'id' ] )
expect ( result . category_id ) . to eq ( category . id )
expect ( result . visible ) . to eq ( true )
end
end
end
end
2018-04-09 13:01:16 +08:00
describe " crawler " do
context " when not a crawler " do
it " renders with the application layout " do
get topic . url
body = response . body
expect ( body ) . to have_tag ( :script , with : { src : '/assets/application.js' } )
expect ( body ) . to have_tag ( :meta , with : { name : 'fragment' } )
end
end
context " when a crawler " do
2019-06-05 09:24:52 +08:00
it " renders with the crawler layout, and handles proper pagination " do
page1_time = 3 . months . ago
page2_time = 2 . months . ago
page3_time = 1 . month . ago
2018-04-13 12:58:33 +08:00
freeze_time page1_time
2019-06-05 09:24:52 +08:00
topic = Fabricate ( :topic )
2018-06-05 15:29:17 +08:00
Fabricate ( :post , topic : topic )
Fabricate ( :post , topic : topic )
2018-04-13 12:58:33 +08:00
freeze_time page2_time
2018-06-05 15:29:17 +08:00
Fabricate ( :post , topic : topic )
Fabricate ( :post , topic : topic )
2018-04-13 12:58:33 +08:00
freeze_time page3_time
2018-06-05 15:29:17 +08:00
Fabricate ( :post , topic : topic )
2018-04-09 13:01:16 +08:00
# ugly, but no inteface to set this and we don't want to create
# 100 posts to test this thing
TopicView . stubs ( :chunk_size ) . returns ( 2 )
2019-06-05 09:24:52 +08:00
user_agent = " Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) "
2018-04-09 13:01:16 +08:00
2019-06-05 09:24:52 +08:00
get topic . url , env : { " HTTP_USER_AGENT " = > user_agent }
2018-04-09 13:01:16 +08:00
2019-06-05 09:24:52 +08:00
body = response . body
2018-04-09 13:01:16 +08:00
2019-06-05 09:24:52 +08:00
expect ( body ) . to have_tag ( :body , with : { class : 'crawler' } )
expect ( body ) . to_not have_tag ( :meta , with : { name : 'fragment' } )
expect ( body ) . to include ( '<link rel="next" href="' + topic . relative_url + " ?page=2 " )
2018-04-13 12:58:33 +08:00
2019-06-05 09:24:52 +08:00
expect ( response . headers [ 'Last-Modified' ] ) . to eq ( page1_time . httpdate )
2018-04-09 13:01:16 +08:00
2019-06-05 09:32:47 +08:00
get topic . url + " ?page=2 " , env : { " HTTP_USER_AGENT " = > user_agent }
2019-06-05 09:24:52 +08:00
body = response . body
expect ( response . headers [ 'Last-Modified' ] ) . to eq ( page2_time . httpdate )
expect ( body ) . to include ( '<link rel="prev" href="' + topic . relative_url )
expect ( body ) . to include ( '<link rel="next" href="' + topic . relative_url + " ?page=3 " )
2019-06-05 09:32:47 +08:00
get topic . url + " ?page=3 " , env : { " HTTP_USER_AGENT " = > user_agent }
2019-06-05 09:24:52 +08:00
body = response . body
2018-04-13 12:58:33 +08:00
2019-06-05 09:24:52 +08:00
expect ( response . headers [ 'Last-Modified' ] ) . to eq ( page3_time . httpdate )
expect ( body ) . to include ( '<link rel="prev" href="' + topic . relative_url + " ?page=2 " )
end
2018-04-09 13:01:16 +08:00
2020-03-09 22:31:24 +08:00
context " canonical_url " do
fab! ( :topic_embed ) { Fabricate ( :topic_embed , embed_url : " https://markvanlan.com " ) }
let ( :user_agent ) { " Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) " }
it " set to topic.url when embed_set_canonical_url is false " do
get topic_embed . topic . url , env : { " HTTP_USER_AGENT " = > user_agent }
expect ( response . body ) . to include ( '<link rel="canonical" href="' + topic_embed . topic . url )
end
it " set to topic_embed.embed_url when embed_set_canonical_url is true " do
SiteSetting . embed_set_canonical_url = true
get topic_embed . topic . url , env : { " HTTP_USER_AGENT " = > user_agent }
expect ( response . body ) . to include ( '<link rel="canonical" href="' + topic_embed . embed_url )
end
end
2019-06-05 09:24:52 +08:00
context " wayback machine " do
it " renders crawler layout " do
get topic . url , env : { " HTTP_USER_AGENT " = > " Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 " , " HTTP_VIA " = > " HTTP/1.0 web.archive.org (Wayback Save Page) " }
2019-06-03 10:13:32 +08:00
body = response . body
2018-04-09 13:01:16 +08:00
2019-06-05 09:24:52 +08:00
expect ( body ) . to have_tag ( :body , with : { class : 'crawler' } )
expect ( body ) . to_not have_tag ( :meta , with : { name : 'fragment' } )
2019-06-03 10:13:32 +08:00
end
2018-04-09 13:01:16 +08:00
end
end
end
2018-08-10 08:51:03 +08:00
describe " # reset_bump_date " do
context " errors " do
let ( :topic ) { Fabricate ( :topic ) }
it " needs you to be logged in " do
put " /t/ #{ topic . id } /reset-bump-date.json "
expect ( response . status ) . to eq ( 403 )
end
2019-01-02 23:57:05 +08:00
[ :user ] . each do | user |
2018-08-10 08:51:03 +08:00
it " denies access for #{ user } " do
sign_in ( Fabricate ( user ) )
put " /t/ #{ topic . id } /reset-bump-date.json "
expect ( response . status ) . to eq ( 403 )
end
end
it " should fail for non-existend topic " do
2019-05-08 07:31:47 +08:00
max_id = Topic . maximum ( :id )
2019-05-06 18:00:22 +08:00
sign_in ( admin )
2019-05-08 07:31:47 +08:00
put " /t/ #{ max_id + 1 } /reset-bump-date.json "
2018-08-10 08:51:03 +08:00
expect ( response . status ) . to eq ( 404 )
end
end
2019-01-02 23:57:05 +08:00
[ :admin , :moderator , :trust_level_4 ] . each do | user |
2018-08-10 08:51:03 +08:00
it " should reset bumped_at as #{ user } " do
sign_in ( Fabricate ( user ) )
topic = Fabricate ( :topic , bumped_at : 1 . hour . ago )
timestamp = 1 . day . ago
Fabricate ( :post , topic : topic , created_at : timestamp )
put " /t/ #{ topic . id } /reset-bump-date.json "
expect ( response . status ) . to eq ( 200 )
2020-03-11 05:13:17 +08:00
expect ( topic . reload . bumped_at ) . to eq_time ( timestamp )
2018-08-10 08:51:03 +08:00
end
end
end
2017-08-24 11:01:11 +08:00
end