FEATURE: reply as new message to the same recipients

This commit is contained in:
Leo McArdle 2016-11-29 17:59:42 +00:00 committed by Guo Xiang Tan
parent c01cee4aa6
commit c76f6856ea
10 changed files with 99 additions and 10 deletions

View File

@ -57,6 +57,7 @@ export default Ember.Controller.extend({
application: Ember.inject.controller(),
replyAsNewTopicDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_TOPIC_KEY),
replyAsNewPrivateMessageDraft: Em.computed.equal('model.draftKey', Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY),
checkedMessages: false,
messageCount: null,
showEditReason: false,
@ -478,7 +479,7 @@ export default Ember.Controller.extend({
}
// If user "created a new topic/post" or "replied as a new topic" successfully, remove the draft.
if (result.responseJson.action === "create_post" || this.get('replyAsNewTopicDraft')) {
if (result.responseJson.action === "create_post" || self.get('replyAsNewTopicDraft') || self.get('replyAsNewPrivateMessageDraft')) {
this.destroyDraft();
}
if (this.get('model.action') === 'edit') {

View File

@ -656,11 +656,31 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
const quotedText = Quote.build(post, quoteState.buffer);
quoteState.clear();
composerController.open({
action: Composer.CREATE_TOPIC,
draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY,
categoryId: this.get('model.category.id')
}).then(() => {
var options;
if (this.get('model.isPrivateMessage')) {
let users = this.get('model.details.allowed_users');
let groups = this.get('model.details.allowed_groups');
let usernames = [];
users.forEach(user => usernames.push(user.username));
groups.forEach(group => usernames.push(group.name));
usernames = usernames.join();
options = {
action: Composer.PRIVATE_MESSAGE,
archetypeId: 'private_message',
draftKey: Composer.REPLY_AS_NEW_PRIVATE_MESSAGE_KEY,
usernames: usernames
};
} else {
options = {
action: Composer.CREATE_TOPIC,
draftKey: Composer.REPLY_AS_NEW_TOPIC_KEY,
categoryId: this.get('model.category.id')
};
}
composerController.open(options).then(() => {
return Em.isEmpty(quotedText) ? "" : quotedText;
}).then(q => {
const postUrl = `${location.protocol}//${location.host}${post.get('url')}`;

View File

@ -18,6 +18,7 @@ const CLOSED = 'closed',
REPLY = 'reply',
EDIT = 'edit',
REPLY_AS_NEW_TOPIC_KEY = "reply_as_new_topic",
REPLY_AS_NEW_PRIVATE_MESSAGE_KEY = "reply_as_new_private_message",
// When creating, these fields are moved into the post model from the composer model
_create_serializer = {
@ -814,7 +815,8 @@ Composer.reopenClass({
EDIT,
// Draft key
REPLY_AS_NEW_TOPIC_KEY
REPLY_AS_NEW_TOPIC_KEY,
REPLY_AS_NEW_PRIVATE_MESSAGE_KEY
});
export default Composer;

View File

@ -15,7 +15,11 @@
{{#if topic.details.can_reply_as_new_topic}}
<div class='reply-as-new-topic'>
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_topic'}} title={{i18n 'post.reply_as_new_topic'}}>{{fa-icon "plus"}}{{i18n 'topic.create'}}</a>
{{#if topic.isPrivateMessage}}
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_private_message'}} title={{i18n 'post.reply_as_new_private_message'}}>{{fa-icon "plus"}}{{i18n 'user.new_private_message'}}</a>
{{else}}
<a href {{action "replyAsNewTopic"}} aria-label={{i18n 'post.reply_as_new_topic'}} title={{i18n 'post.reply_as_new_topic'}}>{{fa-icon "plus"}}{{i18n 'topic.create'}}</a>
{{/if}}
</div>
{{/if}}

View File

@ -1707,6 +1707,7 @@ en:
wiki_last_edited_on: "wiki last edited on"
last_edited_on: "post last edited on"
reply_as_new_topic: "Reply as linked Topic"
reply_as_new_private_message: "Reply as new message to the same recipients"
continue_discussion: "Continuing the discussion from {{postLink}}:"
follow_quote: "go to the quoted post"
show_full: "Show Full Post"

View File

@ -69,7 +69,7 @@ module TopicGuardian
end
def can_reply_as_new_topic?(topic)
authenticated? && topic && !topic.private_message? && @user.has_trust_level?(TrustLevel[1])
authenticated? && topic && @user.has_trust_level?(TrustLevel[1])
end
def can_see_deleted_topics?

View File

@ -218,6 +218,7 @@ describe Guardian do
describe 'can_reply_as_new_topic' do
let(:user) { Fabricate(:user) }
let(:topic) { Fabricate(:topic) }
let(:private_message) { Fabricate(:private_message_topic) }
it "returns false for a non logged in user" do
expect(Guardian.new(nil).can_reply_as_new_topic?(topic)).to be_falsey
@ -235,6 +236,10 @@ describe Guardian do
it "returns true for a trusted user" do
expect(Guardian.new(user).can_reply_as_new_topic?(topic)).to be_truthy
end
it "returns true for a private message" do
expect(Guardian.new(user).can_reply_as_new_topic?(private_message)).to be_truthy
end
end
describe 'can_see_post_actors?' do

View File

@ -72,3 +72,57 @@ test("Marking a topic as wiki", () => {
ok(find('a.wiki').length === 1, 'it shows the wiki icon');
});
});
test("Reply as new topic", () => {
visit("/t/internationalization-localization/280");
click("button.share:eq(0)");
click(".reply-as-new-topic a");
andThen(() => {
ok(exists('.d-editor-input'), 'the composer input is visible');
equal(
find('.d-editor-input').val().trim(),
"Continuing the discussion from [Internationalization / localization](http://localhost:3000/t/internationalization-localization/280):",
"it fills composer with the ring string"
);
equal(
find('#select2-chosen-1').text().trim(), "feature",
"it fills category selector with the right category"
);
});
});
test("Reply as new message", () => {
visit("/t/pm-for-testing/12");
click("button.share:eq(0)");
click(".reply-as-new-topic a");
andThen(() => {
ok(exists('.d-editor-input'), 'the composer input is visible');
equal(
find('.d-editor-input').val().trim(),
"Continuing the discussion from [PM for testing](http://localhost:3000/t/pm-for-testing/12):",
"it fills composer with the ring string"
);
const targets = find('.item span', '.composer-fields');
equal(
$(targets[0]).text(), "someguy",
"it fills up the composer with the right user to start the PM to"
);
equal(
$(targets[1]).text(), "test",
"it fills up the composer with the right user to start the PM to"
);
equal(
$(targets[2]).text(), "Group",
"it fills up the composer with the right group to start the PM to"
);
});
});

File diff suppressed because one or more lines are too long

View File

@ -118,6 +118,7 @@ export default function() {
this.get("/t/280.json", () => response(fixturesByUrl['/t/280/1.json']));
this.get("/t/28830.json", () => response(fixturesByUrl['/t/28830/1.json']));
this.get("/t/9.json", () => response(fixturesByUrl['/t/9/1.json']));
this.get("/t/12.json", () => response(fixturesByUrl['/t/12/1.json']));
this.get("/t/id_for/:slug", () => {
return response({id: 280, slug: "internationalization-localization", url: "/t/internationalization-localization/280"});