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('');
+
+ 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 = '';
+
+ 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