1
0
mirror of https://github.com/discourse/discourse.git synced 2025-03-09 14:34:35 +00:00
Bianca Nenciu 08ab09c928
FIX: Remove public topic invite functionality ()
This can no longer be used from the user interface and could be used to
generate useless topic invites notifications. This commit adds site 
setting max_topic_invitations_per_minute to prevent invite spam.
2022-10-10 19:21:51 +03:00

659 lines
22 KiB
Ruby

# frozen_string_literal: true
require 'swagger_helper'
RSpec.describe 'topics' do
let(:'Api-Key') { Fabricate(:api_key).key }
let(:'Api-Username') { 'system' }
path '/t/{id}/posts.json' do
get 'Get specific posts from a topic' do
tags 'Topics'
operationId 'getSpecificPostsFromTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :post_body, in: :body, schema: {
type: :object,
properties: {
'post_ids[]': { type: :integer }
}, required: [ 'post_ids[]' ]
}
produces 'application/json'
response '200', 'specific posts' do
schema type: :object, properties: {
post_stream: {
type: :object,
properties: {
posts: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
name: { type: [:string, :null] },
username: { type: :string },
avatar_template: { type: :string },
created_at: { type: :string },
cooked: { type: :string },
post_number: { type: :integer },
post_type: { type: :integer },
updated_at: { type: :string },
reply_count: { type: :integer },
reply_to_post_number: { type: [:string, :null] },
quote_count: { type: :integer },
incoming_link_count: { type: :integer },
reads: { type: :integer },
readers_count: { type: :integer },
score: { type: :integer },
yours: { type: :boolean },
topic_id: { type: :integer },
topic_slug: { type: :string },
display_username: { type: [:string, :null] },
primary_group_name: { type: [:string, :null] },
flair_name: { type: [:string, :null] },
flair_url: { type: [:string, :null] },
flair_bg_color: { type: [:string, :null] },
flair_color: { type: [:string, :null] },
version: { type: :integer },
can_edit: { type: :boolean },
can_delete: { type: :boolean },
can_recover: { type: :boolean },
can_wiki: { type: :boolean },
read: { type: :boolean },
user_title: { type: [:string, :null] },
actions_summary: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
can_act: { type: :boolean },
}
},
},
moderator: { type: :boolean },
admin: { type: :boolean },
staff: { type: :boolean },
user_id: { type: :integer },
hidden: { type: :boolean },
trust_level: { type: :integer },
deleted_at: { type: [:string, :null] },
user_deleted: { type: :boolean },
edit_reason: { type: [:string, :null] },
can_view_edit_history: { type: :boolean },
wiki: { type: :boolean },
reviewable_id: { type: :integer },
reviewable_score_count: { type: :integer },
reviewable_score_pending_count: { type: :integer },
}
},
},
}
},
id: { type: :integer },
}
let(:post_body) { { 'post_ids[]': 1 } }
let(:id) { Fabricate(:topic).id }
run_test!
end
end
end
path '/t/{id}.json' do
get 'Get a single topic' do
tags 'Topics'
operationId 'getTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
expected_request_schema = nil
produces 'application/json'
response '200', 'specific posts' do
let(:id) { Fabricate(:topic).id }
expected_response_schema = load_spec_schema('topic_show_response')
schema expected_response_schema
it_behaves_like "a JSON endpoint", 200 do
let(:expected_response_schema) { expected_response_schema }
let(:expected_request_schema) { expected_request_schema }
end
end
end
delete 'Remove a topic' do
tags 'Topics'
operationId 'removeTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
response '200', 'specific posts' do
let!(:post) { Fabricate(:post) }
let(:id) { post.topic.id }
run_test!
end
end
end
path '/t/-/{id}.json' do
put 'Update a topic' do
tags 'Topics'
operationId 'updateTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :post_body, in: :body, schema: {
type: :object,
properties: {
topic: {
type: :object,
properties: {
title: { type: :string },
category_id: { type: :integer },
}
}
}
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
basic_topic: {
type: :object,
properties: {
id: { type: :integer },
title: { type: :string },
fancy_title: { type: :string },
slug: { type: :string },
posts_count: { type: :integer },
}
},
}
let(:post_body) { { title: 'New topic title' } }
let!(:post) { Fabricate(:post) }
let(:id) { post.topic.id }
run_test! do |response|
data = JSON.parse(response.body)
expect(data['basic_topic']['title']).to eq("New topic title")
end
end
end
end
path '/t/{id}/invite.json' do
post 'Invite to topic' do
tags 'Topics', 'Invites'
operationId 'inviteToTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :request_body, in: :body, schema: {
type: :object,
properties: {
user: { type: :string },
email: { type: :string },
}
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
user: {
type: :object,
properties: {
id: { type: :integer },
username: { type: :string },
name: { type: :string },
avatar_template: { type: :string },
}
},
}
let(:username) { Fabricate(:user).username }
let(:request_body) { { user: username } }
let(:id) { Fabricate(:private_message_topic).id }
run_test! do |response|
data = JSON.parse(response.body)
expect(data['user']['username']).to eq(username)
end
end
end
end
path '/t/{id}/bookmark.json' do
put 'Bookmark topic' do
tags 'Topics'
operationId 'bookmarkTopic'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
produces 'application/json'
response '200', 'topic updated' do
let!(:post) { Fabricate(:post) }
let(:id) { post.topic.id }
run_test!
end
end
end
path '/t/{id}/status.json' do
put 'Update the status of a topic' do
tags 'Topics'
operationId 'updateTopicStatus'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :request_body, in: :body, schema: {
type: :object,
properties: {
status: {
type: :string,
enum: ['closed', 'pinned', 'pinned_globally', 'archived', 'visible'],
},
enabled: {
type: :string,
enum: ['true', 'false']
},
until: {
type: :string,
description: 'Only required for `pinned` and `pinned_globally`',
example: '2030-12-31'
}
}, required: [ 'status', 'enabled' ]
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
success: { type: :string, example: "OK" },
topic_status_update: { type: [:string, :null] },
}
let(:request_body) { { status: 'closed', enabled: 'true' } }
let(:id) { Fabricate(:topic).id }
run_test!
end
end
end
path '/latest.json' do
get 'Get the latest topics' do
tags 'Topics'
operationId 'listLatestTopics'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter(
name: :order,
in: :query,
type: :string,
description: 'Enum: `default`, `created`, `activity`, `views`, `posts`, `category`, `likes`, `op_likes`, `posters`')
parameter(
name: :ascending,
in: :query,
type: :string,
description: 'Defaults to `desc`, add `ascending=true` to sort asc')
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
users: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
username: { type: :string },
name: { type: [:string, :null] },
avatar_template: { type: :string },
}
},
},
primary_groups: {
type: :array,
items: {
},
},
topic_list: {
type: :object,
properties: {
can_create_topic: { type: :boolean },
draft: { type: [:string, :null] },
draft_key: { type: :string },
draft_sequence: { type: :integer },
per_page: { type: :integer },
topics: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
title: { type: :string },
fancy_title: { type: :string },
slug: { type: :string },
posts_count: { type: :integer },
reply_count: { type: :integer },
highest_post_number: { type: :integer },
image_url: { type: :string },
created_at: { type: :string },
last_posted_at: { type: :string },
bumped: { type: :boolean },
bumped_at: { type: :string },
archetype: { type: :string },
unseen: { type: :boolean },
last_read_post_number: { type: :integer },
unread_posts: { type: :integer },
pinned: { type: :boolean },
unpinned: { type: [:string, :null] },
visible: { type: :boolean },
closed: { type: :boolean },
archived: { type: :boolean },
notification_level: { type: :integer },
bookmarked: { type: :boolean },
liked: { type: :boolean },
views: { type: :integer },
like_count: { type: :integer },
has_summary: { type: :boolean },
last_poster_username: { type: :string },
category_id: { type: :integer },
op_like_count: { type: :integer },
pinned_globally: { type: :boolean },
featured_link: { type: [:string, :null] },
posters: {
type: :array,
items: {
type: :object,
properties: {
extras: { type: :string },
description: { type: :string },
user_id: { type: :integer },
primary_group_id: { type: [:string, :null] },
}
},
},
}
},
},
}
},
}
let(:order) { 'default' }
let(:ascending) { 'false' }
run_test!
end
end
end
path '/top.json' do
get 'Get the top topics filtered by period' do
tags 'Topics'
operationId 'listTopTopics'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter(
name: :period,
in: :query,
type: :string,
description: 'Enum: `all`, `yearly`, `quarterly`, `monthly`, `weekly`, `daily`')
produces 'application/json'
response '200', 'response' do
schema type: :object, properties: {
users: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
username: { type: :string },
name: { type: :string },
avatar_template: { type: :string },
}
},
},
primary_groups: {
type: :array,
items: {
},
},
topic_list: {
type: :object,
properties: {
can_create_topic: { type: :boolean },
draft: { type: [:string, :null] },
draft_key: { type: :string },
draft_sequence: { type: :integer },
for_period: { type: :string },
per_page: { type: :integer },
topics: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
title: { type: :string },
fancy_title: { type: :string },
slug: { type: :string },
posts_count: { type: :integer },
reply_count: { type: :integer },
highest_post_number: { type: :integer },
image_url: { type: [:string, :null] },
created_at: { type: :string },
last_posted_at: { type: :string },
bumped: { type: :boolean },
bumped_at: { type: :string },
archetype: { type: :string },
unseen: { type: :boolean },
last_read_post_number: { type: :integer },
unread_posts: { type: :integer },
pinned: { type: :boolean },
unpinned: { type: :boolean },
visible: { type: :boolean },
closed: { type: :boolean },
archived: { type: :boolean },
notification_level: { type: :integer },
bookmarked: { type: :boolean },
liked: { type: :boolean },
views: { type: :integer },
like_count: { type: :integer },
has_summary: { type: :boolean },
last_poster_username: { type: :string },
category_id: { type: :integer },
op_like_count: { type: :integer },
pinned_globally: { type: :boolean },
featured_link: { type: [:string, :null] },
posters: {
type: :array,
items: {
type: :object,
properties: {
extras: { type: [:string, :null] },
description: { type: :string },
user_id: { type: :integer },
primary_group_id: { type: [:string, :null] },
}
},
},
}
},
},
}
},
}
let(:period) { 'all' }
run_test!
end
end
end
path '/t/{id}/notifications.json' do
post 'Set notification level' do
tags 'Topics'
operationId 'setNotificationLevel'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :request_body, in: :body, schema: {
type: :object,
properties: {
notification_level: {
type: :string,
enum: ['0', '1', '2', '3'],
}
}, required: [ 'notification_level' ]
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
success: { type: :string, example: "OK" }
}
let(:request_body) { { notification_level: '3' } }
let(:id) { Fabricate(:topic).id }
run_test!
end
end
end
path '/t/{id}/change-timestamp.json' do
put 'Update topic timestamp' do
tags 'Topics'
operationId 'updateTopicTimestamp'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :request_body, in: :body, schema: {
type: :object,
properties: {
timestamp: {
type: :string,
example: '1594291380'
}
}, required: [ 'timestamp' ]
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
success: { type: :string, example: "OK" }
}
let(:request_body) { { timestamp: '1594291380' } }
let!(:post) { Fabricate(:post) }
let(:id) { post.topic.id }
run_test!
end
end
end
path '/t/{id}/timer.json' do
post 'Create topic timer' do
tags 'Topics'
operationId 'createTopicTimer'
consumes 'application/json'
parameter name: 'Api-Key', in: :header, type: :string, required: true
parameter name: 'Api-Username', in: :header, type: :string, required: true
parameter name: :id, in: :path, schema: { type: :string }
parameter name: :request_body, in: :body, schema: {
type: :object,
properties: {
time: {
type: :string,
example: ''
},
status_type: {
type: :string,
},
based_on_last_post: {
type: :boolean,
},
category_id: {
type: :integer
}
}
}
produces 'application/json'
response '200', 'topic updated' do
schema type: :object, properties: {
success: { type: :string, example: "OK" },
execute_at: { type: :string },
duration: { type: [:string, :null] },
based_on_last_post: { type: :boolean },
closed: { type: :boolean },
category_id: { type: [:string, :null] },
}
let(:request_body) { { time: Time.current + 1.day, status_type: 'close' } }
let!(:topic_post) { Fabricate(:post) }
let(:id) { topic_post.topic.id }
run_test!
end
end
end
path '/t/external_id/{external_id}.json' do
get 'Get topic by external_id' do
tags 'Topics'
operationId 'getTopicByExternalId'
consumes 'application/json'
parameter name: :external_id, in: :path, type: :string, required: true
expected_request_schema = nil
produces 'application/json'
response '301', 'redirects to /t/{topic_id}.json' do
expected_response_schema = nil
schema expected_response_schema
let(:topic) { Fabricate(:topic, external_id: 'external_id_1') }
let(:external_id) { topic.external_id }
run_test! do |response|
expect(response).to redirect_to(topic.relative_url + ".json")
end
end
end
end
end