Shows who deleted a post

This commit is contained in:
Robin Ward
2013-07-10 16:19:42 -04:00
parent 8888ae4b40
commit 8ffe9e28d6
8 changed files with 80 additions and 47 deletions

View File

@ -22,17 +22,22 @@ Discourse.ActionSummary = Discourse.Model.extend({
} }
}.property('count', 'acted', 'actionType'), }.property('count', 'acted', 'actionType'),
canAlsoAction: function() { canAlsoAction: Em.computed.and('can_act', 'actionType.notCustomFlag'),
if (this.get('hidden')) return false; usersCollapsed: Em.computed.not('usersExpanded'),
return this.get('can_act'); usersExpanded: Em.computed.gt('users.length', 0),
}.property('can_act', 'hidden'),
// Remove it // Remove it
removeAction: function() { removeAction: function() {
this.set('acted', false); this.setProperties({
this.set('count', this.get('count') - 1); acted: false,
this.set('can_act', true); count: this.get('count') - 1,
return this.set('can_undo', false); can_act: true,
can_undo: false
});
if (this.get('usersExpanded')) {
this.get('users').removeObject(Discourse.User.current());
}
}, },
// Perform this action // Perform this action
@ -42,10 +47,12 @@ Discourse.ActionSummary = Discourse.Model.extend({
var action = this.get('actionType.name_key'); var action = this.get('actionType.name_key');
// Mark it as acted // Mark it as acted
this.set('acted', true); this.setProperties({
this.set('count', this.get('count') + 1); acted: true,
this.set('can_act', false); count: this.get('count') + 1,
this.set('can_undo', true); can_act: false,
can_undo: true
});
if(action === 'notify_moderators' || action === 'notify_user') { if(action === 'notify_moderators' || action === 'notify_user') {
this.set('can_undo',false); this.set('can_undo',false);
@ -53,8 +60,8 @@ Discourse.ActionSummary = Discourse.Model.extend({
} }
// Add ourselves to the users who liked it if present // Add ourselves to the users who liked it if present
if (this.present('users')) { if (this.get('usersExpanded')) {
this.users.pushObject(Discourse.User.current()); this.get('users').addObject(Discourse.User.current());
} }
// Create our post action // Create our post action
@ -113,7 +120,11 @@ Discourse.ActionSummary = Discourse.Model.extend({
var users = Em.A(); var users = Em.A();
actionSummary.set('users', users); actionSummary.set('users', users);
_.each(result,function(user) { _.each(result,function(user) {
if (user.id === Discourse.User.current('id')) {
users.pushObject(Discourse.User.current());
} else {
users.pushObject(Discourse.User.create(user)); users.pushObject(Discourse.User.create(user));
}
}); });
}); });
} }

View File

@ -186,6 +186,11 @@ Discourse.Post = Discourse.Model.extend({
}, },
recover: function() { recover: function() {
this.setProperties({
deleted_at: null,
deleted_by: null
});
return Discourse.ajax("/posts/" + (this.get('id')) + "/recover", { type: 'PUT', cache: false }); return Discourse.ajax("/posts/" + (this.get('id')) + "/recover", { type: 'PUT', cache: false });
}, },

View File

@ -6,7 +6,9 @@
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.PostActionType = Discourse.Model.extend({}); Discourse.PostActionType = Discourse.Model.extend({
notCustomFlag: Em.computed.not('is_custom_flag')
});
Discourse.PostActionType.reopenClass({ Discourse.PostActionType.reopenClass({
MAX_MESSAGE_LENGTH: 500 MAX_MESSAGE_LENGTH: 500

View File

@ -55,6 +55,13 @@
</div> </div>
{{view Discourse.RepliesView contentBinding="replies" postViewBinding="view"}} {{view Discourse.RepliesView contentBinding="replies" postViewBinding="view"}}
{{view Discourse.ActionsHistoryView contentBinding="actionsHistory"}} {{view Discourse.ActionsHistoryView contentBinding="actionsHistory"}}
{{#if deleted_by}}
<div class='post-actions'>
{{i18n post.deleted_by}} {{avatar deleted_by imageSize="tiny"}}
</div>
{{/if}}
{{view Discourse.TopicSummaryView postBinding="this"}} {{view Discourse.TopicSummaryView postBinding="this"}}
</div> </div>

View File

@ -10,24 +10,27 @@
Discourse.ActionsHistoryView = Discourse.View.extend({ Discourse.ActionsHistoryView = Discourse.View.extend({
tagName: 'section', tagName: 'section',
classNameBindings: [':post-actions', 'hidden'], classNameBindings: [':post-actions', 'hidden'],
hidden: Em.computed.empty('content'), hidden: Em.computed.empty('content'),
shouldRerender: Discourse.View.renderIfChanged('content.@each', 'content.users.length'),
shouldRerender: Discourse.View.renderIfChanged('content.@each', 'content.users.@each'),
// This was creating way too many bound ifs and subviews in the handlebars version. // This was creating way too many bound ifs and subviews in the handlebars version.
render: function(buffer) { render: function(buffer) {
if (!this.present('content')) return; if (!this.present('content')) return;
return this.get('content').forEach(function(c) { this.get('content').forEach(function(c) {
var actionString, iconsHtml;
buffer.push("<div class='post-action'>"); buffer.push("<div class='post-action'>");
var renderActionIf = function(property, dataAttribute, text) {
if (!c.get(property)) { return; }
buffer.push(" <a href='#' data-" + dataAttribute + "='" + c.get('id') + "'>" + text + "</a>.");
};
// TODO multi line expansion for flags // TODO multi line expansion for flags
var iconsHtml = "";
if (c.get('usersExpanded')) {
var postUrl; var postUrl;
if (c.get('users')) {
iconsHtml = "";
c.get('users').forEach(function(u) { c.get('users').forEach(function(u) {
console.log(u);
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + (u.get('username_lower')) + "\">"; iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + (u.get('username_lower')) + "\">";
if (u.post_url) { if (u.post_url) {
postUrl = postUrl || u.post_url; postUrl = postUrl || u.post_url;
@ -42,44 +45,35 @@ Discourse.ActionsHistoryView = Discourse.View.extend({
}); });
var key = 'post.actions.people.' + c.get('actionType.name_key'); var key = 'post.actions.people.' + c.get('actionType.name_key');
if(postUrl) { if (postUrl) { key = key + "_with_url"; }
key = key + "_with_url";
}
buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + "."); buffer.push(" " + I18n.t(key, { icons: iconsHtml, postUrl: postUrl}) + ".");
} else {
buffer.push("<a href='#' data-who-acted='" + (c.get('id')) + "'>" + (c.get('description')) + "</a>.");
}
if (c.get('can_act') && !c.get('actionType.is_custom_flag')) {
actionString = I18n.t("post.actions.it_too." + c.get('actionType.name_key'));
buffer.push(" <a href='#' data-act='" + (c.get('id')) + "'>" + actionString + "</a>.");
}
if (c.get('can_undo')) {
actionString = I18n.t("post.actions.undo." + c.get('actionType.name_key') );
buffer.push(" <a href='#' data-undo='" + (c.get('id')) + "'>" + actionString + "</a>.");
}
if (c.get('can_clear_flags')) {
buffer.push(" <a href='#' data-clear-flags='" + (c.get('id')) + "'>" + (I18n.t("post.actions.clear_flags", { count: c.count })) + "</a>.");
} }
renderActionIf('usersCollapsed', 'who-acted', c.get('description'));
renderActionIf('canAlsoAction', 'act', I18n.t("post.actions.it_too." + c.get('actionType.name_key')));
renderActionIf('can_undo', 'undo', I18n.t("post.actions.undo." + c.get('actionType.name_key')));
renderActionIf('can_clear_flags', 'clear-flags', I18n.t("post.actions.clear_flags", { count: c.count }));
buffer.push("</div>"); buffer.push("</div>");
}); });
}, },
actionTypeById: function(actionTypeId) {
return this.get('content').findProperty('id', actionTypeId);
},
click: function(e) { click: function(e) {
var $target, actionTypeId; var $target = $(e.target),
$target = $(e.target); actionTypeId;
if (actionTypeId = $target.data('clear-flags')) { if (actionTypeId = $target.data('clear-flags')) {
this.get('controller').clearFlags(this.content.findProperty('id', actionTypeId)); this.get('controller').clearFlags(this.actionTypeById(actionTypeId));
return false; return false;
} }
// User wants to know who actioned it // User wants to know who actioned it
if (actionTypeId = $target.data('who-acted')) { if (actionTypeId = $target.data('who-acted')) {
this.get('controller').whoActed(this.content.findProperty('id', actionTypeId)); this.get('controller').whoActed(this.actionTypeById(actionTypeId));
return false; return false;
} }

View File

@ -118,6 +118,14 @@ class PostSerializer < BasicPostSerializer
true true
end end
def deleted_by
BasicUserSerializer.new(object.deleted_by, root: false).as_json
end
def include_deleted_by?
object.deleted_by.present?
end
# Summary of the actions taken on this post # Summary of the actions taken on this post
def actions_summary def actions_summary
result = [] result = []

View File

@ -732,6 +732,7 @@ en:
continue_discussion: "Continuing the discussion from {{postLink}}:" continue_discussion: "Continuing the discussion from {{postLink}}:"
follow_quote: "go to the quoted post" follow_quote: "go to the quoted post"
deleted_by_author: "(post removed by author)" deleted_by_author: "(post removed by author)"
deleted_by: "deleted by"
expand_collapse: "expand/collapse" expand_collapse: "expand/collapse"
has_replies: has_replies:

View File

@ -64,6 +64,11 @@ test('destroy by staff', function() {
present(post.get('deleted_at'), "it has a `deleted_at` field."); present(post.get('deleted_at'), "it has a `deleted_at` field.");
equal(post.get('deleted_by'), user, "it has the user in the `deleted_by` field"); equal(post.get('deleted_by'), user, "it has the user in the `deleted_by` field");
ok(Discourse.ajax.calledOnce, "it made an AJAX call"); ok(Discourse.ajax.calledOnce, "it made an AJAX call");
post.recover();
blank(post.get('deleted_at'), "it clears `deleted_at` when recovering");
blank(post.get('deleted_by'), "it clears `deleted_by` when recovering");
}); });
test('destroy by non-staff', function() { test('destroy by non-staff', function() {