2015-04-01 00:58:56 +08:00
|
|
|
require_dependency 'new_post_manager'
|
2013-02-06 03:16:51 +08:00
|
|
|
require_dependency 'post_creator'
|
2013-03-19 05:52:29 +08:00
|
|
|
require_dependency 'post_destroyer'
|
2016-03-22 07:31:56 +08:00
|
|
|
require_dependency 'post_merger'
|
2013-07-29 10:25:19 +08:00
|
|
|
require_dependency 'distributed_memoizer'
|
2015-04-01 00:58:56 +08:00
|
|
|
require_dependency 'new_post_result_serializer'
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
class PostsController < ApplicationController
|
|
|
|
|
|
|
|
# Need to be logged in for all actions here
|
2016-03-31 21:10:50 +08:00
|
|
|
before_filter :ensure_logged_in, except: [:show, :replies, :by_number, :short_link, :reply_history, :revisions, :latest_revision, :expand_embed, :markdown_id, :markdown_num, :cooked, :latest, :user_posts_feed]
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2016-03-31 21:10:50 +08:00
|
|
|
skip_before_filter :preload_json, :check_xhr, only: [:markdown_id, :markdown_num, :short_link, :latest, :user_posts_feed]
|
2013-04-30 14:29:57 +08:00
|
|
|
|
2014-07-12 05:34:26 +08:00
|
|
|
def markdown_id
|
|
|
|
markdown Post.find(params[:id].to_i)
|
|
|
|
end
|
|
|
|
|
|
|
|
def markdown_num
|
2015-10-19 17:01:29 +08:00
|
|
|
if params[:revision].present?
|
|
|
|
post_revision = find_post_revision_from_topic_id
|
|
|
|
render text: post_revision.modifications[:raw].last, content_type: 'text/plain'
|
|
|
|
else
|
|
|
|
markdown Post.find_by(topic_id: params[:topic_id].to_i, post_number: (params[:post_number] || 1).to_i)
|
|
|
|
end
|
2014-07-12 05:34:26 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def markdown(post)
|
2013-04-30 14:29:57 +08:00
|
|
|
if post && guardian.can_see?(post)
|
|
|
|
render text: post.raw, content_type: 'text/plain'
|
|
|
|
else
|
|
|
|
raise Discourse::NotFound
|
|
|
|
end
|
|
|
|
end
|
2013-04-24 16:05:35 +08:00
|
|
|
|
2015-01-24 13:04:14 +08:00
|
|
|
def latest
|
2015-01-24 13:22:19 +08:00
|
|
|
params.permit(:before)
|
|
|
|
last_post_id = params[:before].to_i
|
|
|
|
last_post_id = Post.last.id if last_post_id <= 0
|
|
|
|
|
2016-03-21 18:22:36 +08:00
|
|
|
if params[:id] == "private_posts"
|
|
|
|
raise Discourse::NotFound if current_user.nil?
|
|
|
|
posts = Post.private_posts
|
|
|
|
.order(created_at: :desc)
|
|
|
|
.where('posts.id <= ?', last_post_id)
|
|
|
|
.where('posts.id > ?', last_post_id - 50)
|
|
|
|
.includes(topic: :category)
|
|
|
|
.includes(user: :primary_group)
|
|
|
|
.includes(:reply_to_user)
|
|
|
|
.limit(50)
|
|
|
|
rss_description = I18n.t("rss_description.private_posts")
|
|
|
|
else
|
|
|
|
posts = Post.public_posts
|
|
|
|
.order(created_at: :desc)
|
|
|
|
.where('posts.id <= ?', last_post_id)
|
|
|
|
.where('posts.id > ?', last_post_id - 50)
|
|
|
|
.includes(topic: :category)
|
|
|
|
.includes(user: :primary_group)
|
|
|
|
.includes(:reply_to_user)
|
|
|
|
.limit(50)
|
|
|
|
rss_description = I18n.t("rss_description.posts")
|
|
|
|
end
|
|
|
|
|
2015-01-24 13:04:14 +08:00
|
|
|
# Remove posts the user doesn't have permission to see
|
|
|
|
# This isn't leaking any information we weren't already through the post ID numbers
|
2015-10-16 19:44:48 +08:00
|
|
|
posts = posts.reject { |post| !guardian.can_see?(post) || post.topic.blank? }
|
2015-01-24 13:04:14 +08:00
|
|
|
counts = PostAction.counts_for(posts, current_user)
|
|
|
|
|
2015-06-09 19:39:03 +08:00
|
|
|
respond_to do |format|
|
|
|
|
format.rss do
|
|
|
|
@posts = posts
|
2016-03-21 18:22:36 +08:00
|
|
|
@title = "#{SiteSetting.title} - #{rss_description}"
|
2015-06-09 19:39:03 +08:00
|
|
|
@link = Discourse.base_url
|
2016-03-21 21:15:16 +08:00
|
|
|
@description = rss_description
|
2015-06-09 19:39:03 +08:00
|
|
|
render 'posts/latest', formats: [:rss]
|
|
|
|
end
|
|
|
|
format.json do
|
|
|
|
render_json_dump(serialize_data(posts,
|
|
|
|
PostSerializer,
|
|
|
|
scope: guardian,
|
2016-03-21 18:22:36 +08:00
|
|
|
root: params[:id],
|
2015-06-09 19:39:03 +08:00
|
|
|
add_raw: true,
|
2015-09-02 08:45:09 +08:00
|
|
|
add_title: true,
|
2015-06-09 19:39:03 +08:00
|
|
|
all_post_actions: counts)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2015-01-24 13:04:14 +08:00
|
|
|
end
|
|
|
|
|
2016-03-31 21:10:50 +08:00
|
|
|
def user_posts_feed
|
|
|
|
params.require(:username)
|
|
|
|
user = fetch_user_from_params
|
|
|
|
|
|
|
|
posts = Post.public_posts
|
|
|
|
.where(user_id: user.id)
|
2016-04-01 00:04:53 +08:00
|
|
|
.where(post_type: Post.types[:regular])
|
2016-03-31 21:10:50 +08:00
|
|
|
.order(created_at: :desc)
|
|
|
|
.includes(:user)
|
|
|
|
.includes(topic: :category)
|
|
|
|
.limit(50)
|
|
|
|
|
|
|
|
posts = posts.reject { |post| !guardian.can_see?(post) || post.topic.blank? }
|
|
|
|
|
|
|
|
@posts = posts
|
|
|
|
@title = "#{SiteSetting.title} - #{I18n.t("rss_description.user_posts", username: user.username)}"
|
|
|
|
@link = "#{Discourse.base_url}/users/#{user.username}/activity"
|
|
|
|
@description = I18n.t("rss_description.user_posts", username: user.username)
|
|
|
|
render 'posts/latest', formats: [:rss]
|
|
|
|
end
|
|
|
|
|
2014-06-21 05:06:44 +08:00
|
|
|
def cooked
|
|
|
|
post = find_post_from_params
|
|
|
|
render json: {cooked: post.cooked}
|
|
|
|
end
|
|
|
|
|
2014-10-18 03:18:29 +08:00
|
|
|
def raw_email
|
2016-08-02 05:55:22 +08:00
|
|
|
post = Post.unscoped.find(params[:id].to_i)
|
2014-11-12 21:49:42 +08:00
|
|
|
guardian.ensure_can_view_raw_email!(post)
|
2016-02-02 04:41:49 +08:00
|
|
|
render json: { raw_email: post.raw_email }
|
2014-10-18 03:18:29 +08:00
|
|
|
end
|
|
|
|
|
2013-04-24 16:05:35 +08:00
|
|
|
def short_link
|
|
|
|
post = Post.find(params[:post_id].to_i)
|
2014-07-12 05:34:26 +08:00
|
|
|
# Stuff the user in the request object, because that's what IncomingLink wants
|
|
|
|
if params[:user_id]
|
|
|
|
user = User.find(params[:user_id].to_i)
|
|
|
|
request['u'] = user.username_lower if user
|
|
|
|
end
|
2015-02-05 03:49:05 +08:00
|
|
|
|
|
|
|
guardian.ensure_can_see!(post)
|
2016-11-02 03:20:04 +08:00
|
|
|
redirect_to path(post.url)
|
2013-04-24 16:05:35 +08:00
|
|
|
end
|
2013-02-06 03:16:51 +08:00
|
|
|
|
|
|
|
def create
|
2015-08-06 08:32:53 +08:00
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
@manager_params = create_params
|
2015-08-04 08:55:59 +08:00
|
|
|
@manager_params[:first_post_checks] = !is_api?
|
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
manager = NewPostManager.new(current_user, @manager_params)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
if is_api?
|
|
|
|
memoized_payload = DistributedMemoizer.memoize(signature_for(@manager_params), 120) do
|
|
|
|
result = manager.perform
|
|
|
|
MultiJson.dump(serialize_data(result, NewPostResultSerializer, root: false))
|
|
|
|
end
|
2014-07-14 13:59:58 +08:00
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
parsed_payload = JSON.parse(memoized_payload)
|
|
|
|
backwards_compatible_json(parsed_payload, parsed_payload['success'])
|
2014-07-14 13:59:58 +08:00
|
|
|
else
|
2015-04-01 00:58:56 +08:00
|
|
|
result = manager.perform
|
|
|
|
json = serialize_data(result, NewPostResultSerializer, root: false)
|
|
|
|
backwards_compatible_json(json, result.success?)
|
2014-07-14 13:59:58 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def update
|
2013-06-06 15:14:32 +08:00
|
|
|
params.require(:post)
|
2013-02-07 23:45:24 +08:00
|
|
|
|
2014-01-06 15:12:51 +08:00
|
|
|
post = Post.where(id: params[:id])
|
|
|
|
post = post.with_deleted if guardian.is_staff?
|
|
|
|
post = post.first
|
2015-11-14 00:35:04 +08:00
|
|
|
|
|
|
|
raise Discourse::NotFound if post.blank?
|
|
|
|
|
2013-02-22 07:09:56 +08:00
|
|
|
post.image_sizes = params[:image_sizes] if params[:image_sizes].present?
|
2014-01-07 23:32:09 +08:00
|
|
|
|
2014-02-19 00:19:38 +08:00
|
|
|
if too_late_to(:edit, post)
|
2014-10-28 05:06:43 +08:00
|
|
|
return render json: { errors: [I18n.t('too_late_to_edit')] }, status: 422
|
2014-01-07 23:32:09 +08:00
|
|
|
end
|
|
|
|
|
2013-02-22 07:09:56 +08:00
|
|
|
guardian.ensure_can_edit!(post)
|
|
|
|
|
2014-10-28 05:06:43 +08:00
|
|
|
changes = {
|
|
|
|
raw: params[:post][:raw],
|
|
|
|
edit_reason: params[:post][:edit_reason]
|
|
|
|
}
|
2013-03-27 14:49:23 +08:00
|
|
|
|
2014-10-28 05:06:43 +08:00
|
|
|
# to stay consistent with the create api, we allow for title & category changes here
|
2015-04-24 01:33:29 +08:00
|
|
|
if post.is_first_post?
|
2014-10-28 05:06:43 +08:00
|
|
|
changes[:title] = params[:title] if params[:title]
|
|
|
|
changes[:category_id] = params[:post][:category_id] if params[:post][:category_id]
|
2013-03-27 14:49:23 +08:00
|
|
|
end
|
|
|
|
|
2015-07-29 04:58:56 +08:00
|
|
|
# We don't need to validate edits to small action posts by staff
|
|
|
|
opts = {}
|
|
|
|
if post.post_type == Post.types[:small_action] && current_user.staff?
|
|
|
|
opts[:skip_validations] = true
|
|
|
|
end
|
|
|
|
|
2015-11-14 00:35:04 +08:00
|
|
|
topic = post.topic
|
|
|
|
topic = Topic.with_deleted.find(post.topic_id) if guardian.is_staff?
|
|
|
|
|
|
|
|
revisor = PostRevisor.new(post, topic)
|
2015-08-15 01:33:32 +08:00
|
|
|
revisor.revise!(current_user, changes, opts)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2014-10-28 05:06:43 +08:00
|
|
|
return render_json_error(post) if post.errors.present?
|
2015-11-14 00:35:04 +08:00
|
|
|
return render_json_error(topic) if topic.errors.present?
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-02-22 07:09:56 +08:00
|
|
|
post_serializer = PostSerializer.new(post, scope: guardian, root: false)
|
2015-11-14 00:35:04 +08:00
|
|
|
post_serializer.draft_sequence = DraftSequence.current(current_user, topic.draft_key)
|
|
|
|
link_counts = TopicLink.counts_for(guardian, topic, [post])
|
2013-02-22 07:09:56 +08:00
|
|
|
post_serializer.single_post_link_counts = link_counts[post.id] if link_counts.present?
|
|
|
|
|
2015-04-24 01:33:29 +08:00
|
|
|
result = { post: post_serializer.as_json }
|
2013-02-22 07:09:56 +08:00
|
|
|
if revisor.category_changed.present?
|
2013-05-10 14:47:47 +08:00
|
|
|
result[:category] = BasicCategorySerializer.new(revisor.category_changed, scope: guardian, root: false).as_json
|
2013-02-22 07:09:56 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
render_json_dump(result)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
def show
|
2014-02-25 01:03:29 +08:00
|
|
|
post = find_post_from_params
|
|
|
|
display_post(post)
|
2013-12-12 10:41:34 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def by_number
|
2014-02-25 01:03:29 +08:00
|
|
|
post = find_post_from_params_by_number
|
|
|
|
display_post(post)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-08-07 05:42:36 +08:00
|
|
|
def reply_history
|
2014-02-21 00:38:13 +08:00
|
|
|
post = find_post_from_params
|
2015-09-25 08:15:58 +08:00
|
|
|
render_serialized(post.reply_history(params[:max_replies].to_i, guardian), PostSerializer)
|
2013-08-07 05:42:36 +08:00
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def destroy
|
2013-02-09 06:49:15 +08:00
|
|
|
post = find_post_from_params
|
2015-08-19 03:49:54 +08:00
|
|
|
RateLimiter.new(current_user, "delete_post", 3, 1.minute).performed! unless current_user.staff?
|
2014-01-07 23:32:09 +08:00
|
|
|
|
2014-02-19 00:19:38 +08:00
|
|
|
if too_late_to(:delete_post, post)
|
2014-01-07 23:32:09 +08:00
|
|
|
render json: {errors: [I18n.t('too_late_to_edit')]}, status: 422
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2013-02-08 04:12:55 +08:00
|
|
|
guardian.ensure_can_delete!(post)
|
2013-03-19 05:52:29 +08:00
|
|
|
|
2014-10-01 23:40:13 +08:00
|
|
|
destroyer = PostDestroyer.new(current_user, post, { context: params[:context] })
|
2013-03-19 05:52:29 +08:00
|
|
|
destroyer.destroy
|
|
|
|
|
2013-02-08 04:12:55 +08:00
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2014-04-02 05:45:16 +08:00
|
|
|
def expand_embed
|
2014-04-03 23:30:43 +08:00
|
|
|
render json: {cooked: TopicEmbed.expanded_for(find_post_from_params) }
|
2014-04-03 01:22:10 +08:00
|
|
|
rescue
|
|
|
|
render_json_error I18n.t('errors.embed.load_from_remote')
|
2014-04-02 05:45:16 +08:00
|
|
|
end
|
|
|
|
|
2013-02-08 04:12:55 +08:00
|
|
|
def recover
|
2013-02-09 06:49:15 +08:00
|
|
|
post = find_post_from_params
|
2015-08-19 03:49:54 +08:00
|
|
|
RateLimiter.new(current_user, "delete_post", 3, 1.minute).performed! unless current_user.staff?
|
2013-02-08 04:12:55 +08:00
|
|
|
guardian.ensure_can_recover_post!(post)
|
2013-07-22 15:48:24 +08:00
|
|
|
destroyer = PostDestroyer.new(current_user, post)
|
|
|
|
destroyer.recover
|
|
|
|
post.reload
|
2013-07-10 00:15:55 +08:00
|
|
|
|
2013-07-22 15:48:24 +08:00
|
|
|
render_post_json(post)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def destroy_many
|
2013-06-06 15:14:32 +08:00
|
|
|
params.require(:post_ids)
|
2013-02-06 03:16:51 +08:00
|
|
|
|
2013-09-04 23:53:00 +08:00
|
|
|
posts = Post.where(id: post_ids_including_replies)
|
2013-02-06 03:16:51 +08:00
|
|
|
raise Discourse::InvalidParameters.new(:post_ids) if posts.blank?
|
|
|
|
|
|
|
|
# Make sure we can delete the posts
|
|
|
|
posts.each {|p| guardian.ensure_can_delete!(p) }
|
|
|
|
|
|
|
|
Post.transaction do
|
2013-09-05 08:50:58 +08:00
|
|
|
posts.each {|p| PostDestroyer.new(current_user, p).destroy }
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2016-03-22 07:31:56 +08:00
|
|
|
def merge_posts
|
|
|
|
params.require(:post_ids)
|
|
|
|
posts = Post.where(id: params[:post_ids]).order(:id)
|
|
|
|
raise Discourse::InvalidParameters.new(:post_ids) if posts.pluck(:id) == params[:post_ids]
|
|
|
|
PostMerger.new(current_user, posts).merge
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
# Direct replies to this post
|
|
|
|
def replies
|
2013-02-09 06:49:15 +08:00
|
|
|
post = find_post_from_params
|
2015-09-25 08:15:58 +08:00
|
|
|
replies = post.replies.secured(guardian)
|
|
|
|
render_serialized(replies, PostSerializer)
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
def revisions
|
|
|
|
post_revision = find_post_revision_from_params
|
|
|
|
post_revision_serializer = PostRevisionSerializer.new(post_revision, scope: guardian, root: false)
|
|
|
|
render_json_dump(post_revision_serializer)
|
|
|
|
end
|
|
|
|
|
2014-10-28 05:06:43 +08:00
|
|
|
def latest_revision
|
|
|
|
post_revision = find_latest_post_revision_from_params
|
|
|
|
post_revision_serializer = PostRevisionSerializer.new(post_revision, scope: guardian, root: false)
|
|
|
|
render_json_dump(post_revision_serializer)
|
|
|
|
end
|
|
|
|
|
2014-10-13 16:18:49 +08:00
|
|
|
def hide_revision
|
|
|
|
post_revision = find_post_revision_from_params
|
2014-10-28 05:06:43 +08:00
|
|
|
guardian.ensure_can_hide_post_revision!(post_revision)
|
|
|
|
|
2014-10-13 16:18:49 +08:00
|
|
|
post_revision.hide!
|
2014-10-28 05:06:43 +08:00
|
|
|
|
|
|
|
post = find_post_from_params
|
|
|
|
post.public_version -= 1
|
|
|
|
post.save
|
|
|
|
|
2014-10-13 16:18:49 +08:00
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
|
|
|
def show_revision
|
|
|
|
post_revision = find_post_revision_from_params
|
2014-10-28 05:06:43 +08:00
|
|
|
guardian.ensure_can_show_post_revision!(post_revision)
|
|
|
|
|
2014-10-13 16:18:49 +08:00
|
|
|
post_revision.show!
|
2014-10-28 05:06:43 +08:00
|
|
|
|
|
|
|
post = find_post_from_params
|
|
|
|
post.public_version += 1
|
|
|
|
post.save
|
|
|
|
|
2014-10-13 16:18:49 +08:00
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2016-03-09 23:40:49 +08:00
|
|
|
def revert
|
|
|
|
raise Discourse::NotFound unless guardian.is_staff?
|
|
|
|
|
|
|
|
post_id = params[:id] || params[:post_id]
|
|
|
|
revision = params[:revision].to_i
|
|
|
|
raise Discourse::InvalidParameters.new(:revision) if revision < 2
|
|
|
|
|
|
|
|
post_revision = PostRevision.find_by(post_id: post_id, number: revision)
|
|
|
|
raise Discourse::NotFound unless post_revision
|
|
|
|
|
|
|
|
post = find_post_from_params
|
|
|
|
raise Discourse::NotFound if post.blank?
|
|
|
|
|
|
|
|
post_revision.post = post
|
|
|
|
guardian.ensure_can_see!(post_revision)
|
|
|
|
guardian.ensure_can_edit!(post)
|
|
|
|
return render_json_error(I18n.t('revert_version_same')) if post_revision.modifications["raw"].blank? && post_revision.modifications["title"].blank? && post_revision.modifications["category_id"].blank?
|
|
|
|
|
|
|
|
topic = Topic.with_deleted.find(post.topic_id)
|
|
|
|
|
|
|
|
changes = {}
|
|
|
|
changes[:raw] = post_revision.modifications["raw"][0] if post_revision.modifications["raw"].present? && post_revision.modifications["raw"][0] != post.raw
|
|
|
|
if post.is_first_post?
|
|
|
|
changes[:title] = post_revision.modifications["title"][0] if post_revision.modifications["title"].present? && post_revision.modifications["title"][0] != topic.title
|
|
|
|
changes[:category_id] = post_revision.modifications["category_id"][0] if post_revision.modifications["category_id"].present? && post_revision.modifications["category_id"][0] != topic.category.id
|
|
|
|
end
|
|
|
|
return render_json_error(I18n.t('revert_version_same')) unless changes.length > 0
|
|
|
|
changes[:edit_reason] = "reverted to version ##{post_revision.number.to_i - 1}"
|
|
|
|
|
|
|
|
revisor = PostRevisor.new(post, topic)
|
|
|
|
revisor.revise!(current_user, changes)
|
|
|
|
|
|
|
|
return render_json_error(post) if post.errors.present?
|
|
|
|
return render_json_error(topic) if topic.errors.present?
|
|
|
|
|
|
|
|
post_serializer = PostSerializer.new(post, scope: guardian, root: false)
|
|
|
|
post_serializer.draft_sequence = DraftSequence.current(current_user, topic.draft_key)
|
|
|
|
link_counts = TopicLink.counts_for(guardian, topic, [post])
|
|
|
|
post_serializer.single_post_link_counts = link_counts[post.id] if link_counts.present?
|
|
|
|
|
|
|
|
result = { post: post_serializer.as_json }
|
|
|
|
if post.is_first_post?
|
|
|
|
result[:topic] = BasicTopicSerializer.new(topic, scope: guardian, root: false).as_json if post_revision.modifications["title"].present?
|
|
|
|
result[:category_id] = post_revision.modifications["category_id"][0] if post_revision.modifications["category_id"].present?
|
|
|
|
end
|
|
|
|
|
|
|
|
render_json_dump(result)
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
def bookmark
|
2013-02-09 06:49:15 +08:00
|
|
|
post = find_post_from_params
|
2015-01-12 19:10:15 +08:00
|
|
|
|
|
|
|
if params[:bookmarked] == "true"
|
|
|
|
PostAction.act(current_user, post, PostActionType.types[:bookmark])
|
|
|
|
else
|
|
|
|
PostAction.remove_act(current_user, post, PostActionType.types[:bookmark])
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
2015-01-12 19:10:15 +08:00
|
|
|
|
2015-02-19 07:58:57 +08:00
|
|
|
tu = TopicUser.get(post.topic, current_user)
|
|
|
|
|
2015-02-19 08:42:01 +08:00
|
|
|
render_json_dump(topic_bookmarked: tu.try(:bookmarked))
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|
|
|
|
|
2014-05-13 20:53:11 +08:00
|
|
|
def wiki
|
|
|
|
post = find_post_from_params
|
2016-01-11 23:26:00 +08:00
|
|
|
guardian.ensure_can_wiki!(post)
|
|
|
|
|
2017-01-25 13:34:55 +08:00
|
|
|
post.revise(current_user, { wiki: params[:wiki] })
|
2014-05-13 20:53:11 +08:00
|
|
|
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2014-09-11 05:08:33 +08:00
|
|
|
def post_type
|
|
|
|
guardian.ensure_can_change_post_type!
|
|
|
|
|
|
|
|
post = find_post_from_params
|
2014-10-28 05:06:43 +08:00
|
|
|
post.revise(current_user, { post_type: params[:post_type].to_i })
|
2014-09-11 05:08:33 +08:00
|
|
|
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2014-09-11 22:04:40 +08:00
|
|
|
def rebake
|
|
|
|
guardian.ensure_can_rebake!
|
|
|
|
|
|
|
|
post = find_post_from_params
|
|
|
|
post.rebake!(invalidate_oneboxes: true)
|
|
|
|
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2014-09-23 00:55:13 +08:00
|
|
|
def unhide
|
|
|
|
post = find_post_from_params
|
|
|
|
|
|
|
|
guardian.ensure_can_unhide!(post)
|
|
|
|
|
|
|
|
post.unhide!
|
|
|
|
|
|
|
|
render nothing: true
|
|
|
|
end
|
|
|
|
|
2014-07-17 03:04:55 +08:00
|
|
|
def flagged_posts
|
|
|
|
params.permit(:offset, :limit)
|
|
|
|
guardian.ensure_can_see_flagged_posts!
|
|
|
|
|
|
|
|
user = fetch_user_from_params
|
|
|
|
offset = [params[:offset].to_i, 0].max
|
|
|
|
limit = [(params[:limit] || 60).to_i, 100].min
|
|
|
|
|
2015-04-13 23:48:31 +08:00
|
|
|
posts = user_posts(guardian, user.id, offset: offset, limit: limit)
|
2014-10-09 22:10:16 +08:00
|
|
|
.where(id: PostAction.where(post_action_type_id: PostActionType.notify_flag_type_ids)
|
|
|
|
.where(disagreed_at: nil)
|
2014-07-17 03:04:55 +08:00
|
|
|
.select(:post_id))
|
|
|
|
|
|
|
|
render_serialized(posts, AdminPostSerializer)
|
|
|
|
end
|
|
|
|
|
|
|
|
def deleted_posts
|
|
|
|
params.permit(:offset, :limit)
|
|
|
|
guardian.ensure_can_see_deleted_posts!
|
|
|
|
|
|
|
|
user = fetch_user_from_params
|
|
|
|
offset = [params[:offset].to_i, 0].max
|
|
|
|
limit = [(params[:limit] || 60).to_i, 100].min
|
|
|
|
|
2015-04-13 23:48:31 +08:00
|
|
|
posts = user_posts(guardian, user.id, offset: offset, limit: limit).where.not(deleted_at: nil)
|
2014-07-17 03:04:55 +08:00
|
|
|
|
|
|
|
render_serialized(posts, AdminPostSerializer)
|
|
|
|
end
|
|
|
|
|
2013-02-09 06:49:15 +08:00
|
|
|
protected
|
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
# We can't break the API for making posts. The new, queue supporting API
|
|
|
|
# doesn't return the post as the root JSON object, but as a nested object.
|
|
|
|
# If a param is present it uses that result structure.
|
|
|
|
def backwards_compatible_json(json_obj, success)
|
2015-04-02 02:18:46 +08:00
|
|
|
json_obj.symbolize_keys!
|
2015-08-04 08:55:59 +08:00
|
|
|
if params[:nested_post].blank? && json_obj[:errors].blank? && json_obj[:action] != :enqueued
|
2015-04-02 02:18:46 +08:00
|
|
|
json_obj = json_obj[:post]
|
|
|
|
end
|
|
|
|
|
2016-12-16 09:05:20 +08:00
|
|
|
if !success && GlobalSetting.try(:verbose_api_logging) && (is_api? || is_user_api?)
|
2016-04-13 00:10:23 +08:00
|
|
|
Rails.logger.error "Error creating post via API:\n\n#{json_obj.inspect}"
|
|
|
|
end
|
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
render json: json_obj, status: (!!success) ? 200 : 422
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
def find_post_revision_from_params
|
|
|
|
post_id = params[:id] || params[:post_id]
|
|
|
|
revision = params[:revision].to_i
|
|
|
|
raise Discourse::InvalidParameters.new(:revision) if revision < 2
|
|
|
|
|
2014-05-06 21:41:59 +08:00
|
|
|
post_revision = PostRevision.find_by(post_id: post_id, number: revision)
|
2014-10-28 05:06:43 +08:00
|
|
|
raise Discourse::NotFound unless post_revision
|
|
|
|
|
2014-02-05 03:05:50 +08:00
|
|
|
post_revision.post = find_post_from_params
|
2014-10-28 05:06:43 +08:00
|
|
|
guardian.ensure_can_see!(post_revision)
|
2014-02-05 03:05:50 +08:00
|
|
|
|
2014-10-28 05:06:43 +08:00
|
|
|
post_revision
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_latest_post_revision_from_params
|
|
|
|
post_id = params[:id] || params[:post_id]
|
|
|
|
|
|
|
|
finder = PostRevision.where(post_id: post_id).order(:number)
|
|
|
|
finder = finder.where(hidden: false) unless guardian.is_staff?
|
|
|
|
post_revision = finder.last
|
|
|
|
|
|
|
|
raise Discourse::NotFound unless post_revision
|
|
|
|
|
|
|
|
post_revision.post = find_post_from_params
|
2013-12-12 10:41:34 +08:00
|
|
|
guardian.ensure_can_see!(post_revision)
|
2014-10-28 05:06:43 +08:00
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
post_revision
|
|
|
|
end
|
2013-06-07 15:52:03 +08:00
|
|
|
|
2015-10-19 17:01:29 +08:00
|
|
|
def find_post_revision_from_topic_id
|
|
|
|
post = Post.find_by(topic_id: params[:topic_id].to_i, post_number: (params[:post_number] || 1).to_i)
|
|
|
|
raise Discourse::NotFound unless guardian.can_see?(post)
|
|
|
|
|
|
|
|
revision = params[:revision].to_i
|
|
|
|
raise Discourse::NotFound if revision < 2
|
|
|
|
|
|
|
|
post_revision = PostRevision.find_by(post_id: post.id, number: revision)
|
|
|
|
raise Discourse::NotFound unless post_revision
|
|
|
|
|
|
|
|
post_revision.post = post
|
|
|
|
guardian.ensure_can_see!(post_revision)
|
|
|
|
|
|
|
|
post_revision
|
|
|
|
end
|
|
|
|
|
2013-06-07 15:52:03 +08:00
|
|
|
private
|
|
|
|
|
2015-04-13 23:48:31 +08:00
|
|
|
def user_posts(guardian, user_id, opts)
|
|
|
|
posts = Post.includes(:user, :topic, :deleted_by, :user_actions)
|
|
|
|
.where(user_id: user_id)
|
|
|
|
.with_deleted
|
|
|
|
.order(created_at: :desc)
|
|
|
|
|
|
|
|
if guardian.user.moderator?
|
|
|
|
|
|
|
|
# Awful hack, but you can't seem to remove the `default_scope` when joining
|
|
|
|
# So instead I grab the topics separately
|
|
|
|
topic_ids = posts.dup.pluck(:topic_id)
|
|
|
|
topics = Topic.where(id: topic_ids).with_deleted.where.not(archetype: 'private_message')
|
|
|
|
topics = topics.secured(guardian)
|
|
|
|
|
|
|
|
posts = posts.where(topic_id: topics.pluck(:id))
|
|
|
|
end
|
|
|
|
|
|
|
|
posts.offset(opts[:offset])
|
|
|
|
.limit(opts[:limit])
|
2014-07-17 03:04:55 +08:00
|
|
|
end
|
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
def create_params
|
|
|
|
permitted = [
|
|
|
|
:raw,
|
|
|
|
:topic_id,
|
|
|
|
:archetype,
|
|
|
|
:category,
|
|
|
|
:target_usernames,
|
|
|
|
:reply_to_post_number,
|
2015-08-03 12:29:04 +08:00
|
|
|
:auto_track,
|
|
|
|
:typing_duration_msecs,
|
2016-05-22 16:54:03 +08:00
|
|
|
:composer_open_duration_msecs,
|
2016-07-27 17:50:13 +08:00
|
|
|
:visible
|
2013-12-12 10:41:34 +08:00
|
|
|
]
|
|
|
|
|
|
|
|
# param munging for WordPress
|
|
|
|
params[:auto_track] = !(params[:auto_track].to_s == "false") if params[:auto_track]
|
2016-07-27 17:50:13 +08:00
|
|
|
params[:visible] = (params[:unlist_topic].to_s == "false") if params[:unlist_topic]
|
2013-12-12 10:41:34 +08:00
|
|
|
|
2016-08-26 08:58:34 +08:00
|
|
|
if is_api?
|
2013-12-12 10:41:34 +08:00
|
|
|
# php seems to be sending this incorrectly, don't fight with it
|
|
|
|
params[:skip_validations] = params[:skip_validations].to_s == "true"
|
|
|
|
permitted << :skip_validations
|
2014-04-04 02:42:26 +08:00
|
|
|
|
|
|
|
# We allow `embed_url` via the API
|
|
|
|
permitted << :embed_url
|
2016-05-22 16:54:03 +08:00
|
|
|
|
|
|
|
# We allow `created_at` via the API
|
|
|
|
permitted << :created_at
|
|
|
|
|
2013-12-12 10:41:34 +08:00
|
|
|
end
|
2013-07-02 10:22:56 +08:00
|
|
|
|
2014-09-08 23:11:56 +08:00
|
|
|
result = params.permit(*permitted).tap do |whitelisted|
|
|
|
|
whitelisted[:image_sizes] = params[:image_sizes]
|
|
|
|
# TODO this does not feel right, we should name what meta_data is allowed
|
|
|
|
whitelisted[:meta_data] = params[:meta_data]
|
|
|
|
end
|
|
|
|
|
|
|
|
# Staff are allowed to pass `is_warning`
|
|
|
|
if current_user.staff?
|
|
|
|
params.permit(:is_warning)
|
|
|
|
result[:is_warning] = (params[:is_warning] == "true")
|
2015-04-01 00:58:56 +08:00
|
|
|
else
|
|
|
|
result[:is_warning] = false
|
2013-06-07 15:52:03 +08:00
|
|
|
end
|
2014-09-08 23:11:56 +08:00
|
|
|
|
2015-09-16 00:29:15 +08:00
|
|
|
if current_user.staff? && SiteSetting.enable_whispers? && params[:whisper] == "true"
|
2015-09-11 04:01:23 +08:00
|
|
|
result[:post_type] = Post.types[:whisper]
|
|
|
|
end
|
|
|
|
|
2015-04-18 19:53:53 +08:00
|
|
|
PostRevisor.tracked_topic_fields.each_key do |f|
|
2015-01-28 01:13:45 +08:00
|
|
|
params.permit(f => [])
|
|
|
|
result[f] = params[f] if params.has_key?(f)
|
|
|
|
end
|
2015-01-07 03:53:12 +08:00
|
|
|
|
2015-01-30 02:09:35 +08:00
|
|
|
# Stuff we can use in spam prevention plugins
|
|
|
|
result[:ip_address] = request.remote_ip
|
|
|
|
result[:user_agent] = request.user_agent
|
|
|
|
result[:referrer] = request.env["HTTP_REFERER"]
|
|
|
|
|
2015-12-02 12:49:43 +08:00
|
|
|
if usernames = result[:target_usernames]
|
|
|
|
usernames = usernames.split(",")
|
|
|
|
groups = Group.mentionable(current_user).where('name in (?)', usernames).pluck('name')
|
|
|
|
usernames -= groups
|
|
|
|
result[:target_usernames] = usernames.join(",")
|
|
|
|
result[:target_group_names] = groups.join(",")
|
|
|
|
end
|
|
|
|
|
2014-09-08 23:11:56 +08:00
|
|
|
result
|
2013-12-12 10:41:34 +08:00
|
|
|
end
|
|
|
|
|
2015-04-01 00:58:56 +08:00
|
|
|
def signature_for(args)
|
|
|
|
"post##" << Digest::SHA1.hexdigest(args
|
|
|
|
.to_a
|
|
|
|
.concat([["user", current_user.id]])
|
|
|
|
.sort{|x,y| x[0] <=> y[0]}.join do |x,y|
|
|
|
|
"#{x}:#{y}"
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2014-02-19 00:19:38 +08:00
|
|
|
def too_late_to(action, post)
|
|
|
|
!guardian.send("can_#{action}?", post) && post.user_id == current_user.id && post.edit_time_limit_expired?
|
|
|
|
end
|
|
|
|
|
2014-02-22 00:12:43 +08:00
|
|
|
def display_post(post)
|
|
|
|
post.revert_to(params[:version].to_i) if params[:version].present?
|
|
|
|
render_post_json(post)
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_post_from_params
|
|
|
|
by_id_finder = Post.where(id: params[:id] || params[:post_id])
|
|
|
|
find_post_using(by_id_finder)
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_post_from_params_by_number
|
|
|
|
by_number_finder = Post.where(topic_id: params[:topic_id], post_number: params[:post_number])
|
|
|
|
find_post_using(by_number_finder)
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_post_using(finder)
|
|
|
|
# Include deleted posts if the user is staff
|
|
|
|
finder = finder.with_deleted if current_user.try(:staff?)
|
|
|
|
post = finder.first
|
2014-09-11 09:10:27 +08:00
|
|
|
raise Discourse::NotFound unless post
|
2014-05-12 22:30:10 +08:00
|
|
|
# load deleted topic
|
|
|
|
post.topic = Topic.with_deleted.find(post.topic_id) if current_user.try(:staff?)
|
2014-02-22 00:12:43 +08:00
|
|
|
guardian.ensure_can_see!(post)
|
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2013-02-06 03:16:51 +08:00
|
|
|
end
|