diff --git a/app/assets/javascripts/discourse/controllers/history.js.es6 b/app/assets/javascripts/discourse/controllers/history.js.es6 index 50170a72068..eb35021486e 100644 --- a/app/assets/javascripts/discourse/controllers/history.js.es6 +++ b/app/assets/javascripts/discourse/controllers/history.js.es6 @@ -79,6 +79,27 @@ export default ObjectController.extend(ModalFunctionality, { } }.property("viewMode", "wiki_changes"), + post_type_diff: function () { + var viewMode = this.get("viewMode"); + var changes = this.get("post_type_changes"); + if (changes === null) { return; } + + var moderator = Discourse.Site.currentProp('post_types.moderator_action'); + + if (viewMode === "inline") { + var diff = changes["current_post_type"] === moderator ? + '' : + ''; + return "
" + diff + "
"; + } else { + var prev = changes["previous_post_type"] === moderator ? '' : " "; + var curr = changes["current_post_type"] === moderator ? + '' : + ''; + return "
" + prev + "
" + curr + "
"; + } + }.property("viewMode", "post_type_changes"), + title_diff: function() { var viewMode = this.get("viewMode"); if(viewMode === "side_by_side_markdown") { diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 3737a93be1e..5300e41c5af 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -379,7 +379,20 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, { }, toggleWiki: function(post) { + // the request to the server is made in an observer in the post class post.toggleProperty('wiki'); + }, + + togglePostType: function (post) { + // the request to the server is made in an observer in the post class + var regular = Discourse.Site.currentProp('post_types.regular'), + moderator = Discourse.Site.currentProp('post_types.moderator_action'); + + if (post.get("post_type") === moderator) { + post.set("post_type", regular); + } else { + post.set("post_type", moderator); + } } }, diff --git a/app/assets/javascripts/discourse/models/_post.js b/app/assets/javascripts/discourse/models/_post.js index f2980e50d65..8ca6f0d7d0f 100644 --- a/app/assets/javascripts/discourse/models/_post.js +++ b/app/assets/javascripts/discourse/models/_post.js @@ -76,23 +76,30 @@ Discourse.Post = Discourse.Model.extend({ }.observes('bookmarked'), wikiChanged: function() { - var self = this; + var data = { wiki: this.get("wiki") }; + this._updatePost("wiki", data); + }.observes('wiki'), - Discourse.ajax('/posts/' + this.get('id') + '/wiki', { - type: 'PUT', - data: { - wiki: this.get('wiki') ? true : false - } - }).then(function() { - self.incrementProperty('version'); - }, function(error) { + postTypeChanged: function () { + var data = { post_type: this.get("post_type") }; + this._updatePost("post_type", data); + }.observes("post_type"), + + _updatePost: function (field, data) { + var self = this; + Discourse.ajax("/posts/" + this.get("id") + "/" + field, { + type: "PUT", + data: data + }).then(function () { + self.incrementProperty("version"); + }, function (error) { if (error && error.responseText) { bootbox.alert($.parseJSON(error.responseText).errors[0]); } else { - bootbox.alert(I18n.t('generic_error')); + bootbox.alert(I18n.t("generic_error")); } }); - }.observes('wiki'), + }, internalLinks: function() { if (this.blank('link_counts')) return null; diff --git a/app/assets/javascripts/discourse/templates/modal/history.js.handlebars b/app/assets/javascripts/discourse/templates/modal/history.js.handlebars index e138a47fed4..4ee725d3322 100644 --- a/app/assets/javascripts/discourse/templates/modal/history.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/history.js.handlebars @@ -40,6 +40,11 @@ {{{wiki_diff}}} {{/if}} + {{#if post_type_changes}} +
+ {{{post_type_diff}}} +
+ {{/if}} {{{body_diff}}} diff --git a/app/assets/javascripts/discourse/views/post-menu.js.es6 b/app/assets/javascripts/discourse/views/post-menu.js.es6 index e3fa0766955..25c21e53999 100644 --- a/app/assets/javascripts/discourse/views/post-menu.js.es6 +++ b/app/assets/javascripts/discourse/views/post-menu.js.es6 @@ -275,8 +275,24 @@ export default Discourse.View.extend({ renderAdminPopup: function(post, buffer) { if (!Discourse.User.currentProp('canManageTopic')) { return; } - var wikiText = post.get('wiki') ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki'); - buffer.push('

' + I18n.t('admin_title') + '

'); + + var isWiki = post.get('wiki'), + wikiIcon = '', + wikiText = isWiki ? I18n.t('post.controls.unwiki') : I18n.t('post.controls.wiki'); + + var isModerator = post.get('post_type') === Discourse.Site.currentProp('post_types.moderator_action'), + postTypeIcon = '', + postTypeText = isModerator ? I18n.t('post.controls.revert_to_regular') : I18n.t('post.controls.convert_to_moderator'); + + var html = '
' + + '

' + I18n.t('admin_title') + '

' + + '' + + '
'; + + buffer.push(html); }, clickAdmin: function() { @@ -289,6 +305,10 @@ export default Discourse.View.extend({ this.get('controller').send('toggleWiki', this.get('post')); }, + clickTogglePostType: function () { + this.get("controller").send("togglePostType", this.get("post")); + }, + buttonForShowMoreActions: function() { return new Button('showMoreActions', 'show_more', 'ellipsis-h'); }, diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 8febcf7962d..410898bb9cf 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -241,6 +241,17 @@ class PostsController < ApplicationController render nothing: true end + def post_type + guardian.ensure_can_change_post_type! + + post = find_post_from_params + post.post_type = params[:post_type].to_i + post.version += 1 + post.save + + render nothing: true + end + def flagged_posts params.permit(:offset, :limit) guardian.ensure_can_see_flagged_posts! diff --git a/app/models/post.rb b/app/models/post.rb index 4c5f894a78f..34451ba120d 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -525,7 +525,7 @@ class Post < ActiveRecord::Base end def save_revision - modifications = changes.extract!(:raw, :cooked, :edit_reason, :user_id, :wiki) + modifications = changes.extract!(:raw, :cooked, :edit_reason, :user_id, :wiki, :post_type) # make sure cooked is always present (oneboxes might not change the cooked post) modifications["cooked"] = [self.cooked, self.cooked] unless modifications["cooked"].present? PostRevision.create!( diff --git a/app/models/post_revision.rb b/app/models/post_revision.rb index 45f9e686958..b757efbfac5 100644 --- a/app/models/post_revision.rb +++ b/app/models/post_revision.rb @@ -39,6 +39,17 @@ class PostRevision < ActiveRecord::Base } end + def post_type_changes + prev = lookup("post_type", 0) + cur = lookup("post_type", 1) + return if prev == cur + + { + previous_post_type: prev, + current_post_type: cur, + } + end + def title_changes prev = "
#{CGI::escapeHTML(previous("title"))}
" cur = "
#{CGI::escapeHTML(current("title"))}
" diff --git a/app/serializers/post_revision_serializer.rb b/app/serializers/post_revision_serializer.rb index 55345f6aebd..bd51b6765b9 100644 --- a/app/serializers/post_revision_serializer.rb +++ b/app/serializers/post_revision_serializer.rb @@ -11,7 +11,8 @@ class PostRevisionSerializer < ApplicationSerializer :title_changes, :category_changes, :user_changes, - :wiki_changes + :wiki_changes, + :post_type_changes def include_title_changes? object.has_topic_data? diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 40fa23eefef..66c46be8e60 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1105,6 +1105,8 @@ en: admin: "post admin actions" wiki: "Wiki post" unwiki: "Unwiki post" + revert_to_regular: "Regular post" + convert_to_moderator: "Staff post" actions: flag: 'Flag' diff --git a/config/routes.rb b/config/routes.rb index 654839be257..5e739e2f59e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -263,6 +263,7 @@ Discourse::Application.routes.draw do resources :posts do put "bookmark" put "wiki" + put "post_type" get "replies" get "revisions/:revision" => "posts#revisions" put "recover" diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index ccdc08419af..8218755bf3d 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -165,6 +165,10 @@ module PostGuardian is_staff? || @user.has_trust_level?(TrustLevel[4]) end + def can_change_post_type? + is_staff? + end + def can_see_flagged_posts? is_staff? end diff --git a/spec/models/post_revision_spec.rb b/spec/models/post_revision_spec.rb index d76302ba18f..ab10fac970f 100644 --- a/spec/models/post_revision_spec.rb +++ b/spec/models/post_revision_spec.rb @@ -70,4 +70,12 @@ describe PostRevision do changes[:current_wiki].should be_true end + it "can find post_type changes" do + r = create_rev("post_type" => [1, 2]) + + changes = r.post_type_changes + changes[:previous_post_type].should == 1 + changes[:current_post_type].should == 2 + end + end