mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: custom email message for topic invites
This commit is contained in:
parent
b624c5cc94
commit
4253141700
@ -74,10 +74,9 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||||||
return this.get('isAdmin') && (Discourse.Utilities.emailValid(this.get('emailOrUsername')) || this.get('isPrivateTopic') || !this.get('invitingToTopic')) && !Discourse.SiteSettings.enable_sso && Discourse.SiteSettings.enable_local_logins && !this.get('isMessage');
|
return this.get('isAdmin') && (Discourse.Utilities.emailValid(this.get('emailOrUsername')) || this.get('isPrivateTopic') || !this.get('invitingToTopic')) && !Discourse.SiteSettings.enable_sso && Discourse.SiteSettings.enable_local_logins && !this.get('isMessage');
|
||||||
}.property('isAdmin', 'emailOrUsername', 'isPrivateTopic', 'isMessage', 'invitingToTopic'),
|
}.property('isAdmin', 'emailOrUsername', 'isPrivateTopic', 'isMessage', 'invitingToTopic'),
|
||||||
|
|
||||||
// Show Custom Message textarea? (only shown when inviting new user to forum)
|
|
||||||
showCustomMessage: function() {
|
showCustomMessage: function() {
|
||||||
return this.get('model') === this.currentUser;
|
return (this.get('model') === this.currentUser || Discourse.Utilities.emailValid(this.get('emailOrUsername')));
|
||||||
}.property('model'),
|
}.property('emailOrUsername'),
|
||||||
|
|
||||||
// Instructional text for the modal.
|
// Instructional text for the modal.
|
||||||
inviteInstructions: function() {
|
inviteInstructions: function() {
|
||||||
@ -228,7 +227,11 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||||||
showCustomMessageBox() {
|
showCustomMessageBox() {
|
||||||
this.toggleProperty('hasCustomMessage');
|
this.toggleProperty('hasCustomMessage');
|
||||||
if (this.get('hasCustomMessage')) {
|
if (this.get('hasCustomMessage')) {
|
||||||
this.set('customMessage', I18n.t('invite.custom_message_template'));
|
if (this.get('model') === this.currentUser) {
|
||||||
|
this.set('customMessage', I18n.t('invite.custom_message_template_forum'));
|
||||||
|
} else {
|
||||||
|
this.set('customMessage', I18n.t('invite.custom_message_template_topic'));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.set('customMessage', null);
|
this.set('customMessage', null);
|
||||||
}
|
}
|
||||||
|
@ -309,10 +309,10 @@ const Topic = RestModel.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
createInvite(emailOrUsername, groupNames) {
|
createInvite(user, group_names, custom_message) {
|
||||||
return Discourse.ajax("/t/" + this.get('id') + "/invite", {
|
return Discourse.ajax("/t/" + this.get('id') + "/invite", {
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: { user: emailOrUsername, group_names: groupNames }
|
data: { user, group_names, custom_message }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ class TopicsController < ApplicationController
|
|||||||
guardian.ensure_can_invite_to!(topic,group_ids)
|
guardian.ensure_can_invite_to!(topic,group_ids)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if topic.invite(current_user, username_or_email, group_ids)
|
if topic.invite(current_user, username_or_email, group_ids, params[:custom_message])
|
||||||
user = User.find_by_username_or_email(username_or_email)
|
user = User.find_by_username_or_email(username_or_email)
|
||||||
if user
|
if user
|
||||||
render_json_dump BasicUserSerializer.new(user, scope: guardian, root: 'user')
|
render_json_dump BasicUserSerializer.new(user, scope: guardian, root: 'user')
|
||||||
|
@ -17,6 +17,21 @@ class InviteMailer < ActionMailer::Base
|
|||||||
invitee_name = "#{invite.invited_by.name} (#{invite.invited_by.username})"
|
invitee_name = "#{invite.invited_by.name} (#{invite.invited_by.username})"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# custom message
|
||||||
|
html = nil
|
||||||
|
if custom_message.present? && custom_message =~ /{invite_link}/
|
||||||
|
custom_message.gsub!("{invite_link}", "#{Discourse.base_url}/invites/#{invite.invite_key}")
|
||||||
|
custom_message.gsub!("{site_title}", SiteSetting.title) if custom_message =~ /{site_title}/
|
||||||
|
custom_message.gsub!("{site_description}", SiteSetting.site_description) if custom_message =~ /{site_description}/
|
||||||
|
|
||||||
|
html = UserNotificationRenderer.new(Rails.configuration.paths["app/views"]).render(
|
||||||
|
template: 'email/invite',
|
||||||
|
format: :html,
|
||||||
|
locals: { message: PrettyText.cook(custom_message).html_safe,
|
||||||
|
classes: 'custom-invite-email' }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# If they were invited to a topic
|
# If they were invited to a topic
|
||||||
if first_topic.present?
|
if first_topic.present?
|
||||||
# get topic excerpt
|
# get topic excerpt
|
||||||
@ -25,8 +40,12 @@ class InviteMailer < ActionMailer::Base
|
|||||||
topic_excerpt = first_topic.excerpt.gsub("\n", " ")
|
topic_excerpt = first_topic.excerpt.gsub("\n", " ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
html.gsub!("{topic_title}", first_topic.try(:title)) if html.present? && html =~ /{topic_title}/
|
||||||
|
html.gsub!("{topic_excerpt}", topic_excerpt) if html.present? && html =~ /{topic_excerpt}/
|
||||||
|
|
||||||
build_email(invite.email,
|
build_email(invite.email,
|
||||||
template: 'invite_mailer',
|
template: 'invite_mailer',
|
||||||
|
html_override: html,
|
||||||
invitee_name: invitee_name,
|
invitee_name: invitee_name,
|
||||||
site_domain_name: Discourse.current_hostname,
|
site_domain_name: Discourse.current_hostname,
|
||||||
invite_link: "#{Discourse.base_url}/invites/#{invite.invite_key}",
|
invite_link: "#{Discourse.base_url}/invites/#{invite.invite_key}",
|
||||||
@ -35,20 +54,6 @@ class InviteMailer < ActionMailer::Base
|
|||||||
site_description: SiteSetting.site_description,
|
site_description: SiteSetting.site_description,
|
||||||
site_title: SiteSetting.title)
|
site_title: SiteSetting.title)
|
||||||
else
|
else
|
||||||
html = nil
|
|
||||||
if custom_message.present? && custom_message =~ /{invite_link}/
|
|
||||||
custom_message.gsub!("{invite_link}", "#{Discourse.base_url}/invites/#{invite.invite_key}")
|
|
||||||
custom_message.gsub!("{site_title}", SiteSetting.title) if custom_message =~ /{site_title}/
|
|
||||||
custom_message.gsub!("{site_description}", SiteSetting.site_description) if custom_message =~ /{site_description}/
|
|
||||||
|
|
||||||
html = UserNotificationRenderer.new(Rails.configuration.paths["app/views"]).render(
|
|
||||||
template: 'email/invite',
|
|
||||||
format: :html,
|
|
||||||
locals: { message: PrettyText.cook(custom_message).html_safe,
|
|
||||||
classes: 'custom-invite-email' }
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
build_email(invite.email,
|
build_email(invite.email,
|
||||||
template: 'invite_forum_mailer',
|
template: 'invite_forum_mailer',
|
||||||
html_override: html,
|
html_override: html,
|
||||||
|
@ -591,7 +591,7 @@ class Topic < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Invite a user to the topic by username or email. Returns success/failure
|
# Invite a user to the topic by username or email. Returns success/failure
|
||||||
def invite(invited_by, username_or_email, group_ids=nil)
|
def invite(invited_by, username_or_email, group_ids=nil, custom_message=nil)
|
||||||
if private_message?
|
if private_message?
|
||||||
# If the user exists, add them to the message.
|
# If the user exists, add them to the message.
|
||||||
user = User.find_by_username_or_email(username_or_email)
|
user = User.find_by_username_or_email(username_or_email)
|
||||||
@ -616,7 +616,7 @@ class Topic < ActiveRecord::Base
|
|||||||
RateLimiter.new(invited_by, "topic-invitations-per-day", SiteSetting.max_topic_invitations_per_day, 1.day.to_i).performed!
|
RateLimiter.new(invited_by, "topic-invitations-per-day", SiteSetting.max_topic_invitations_per_day, 1.day.to_i).performed!
|
||||||
|
|
||||||
# NOTE callers expect an invite object if an invite was sent via email
|
# NOTE callers expect an invite object if an invite was sent via email
|
||||||
invite_by_email(invited_by, username_or_email, group_ids)
|
invite_by_email(invited_by, username_or_email, group_ids, custom_message)
|
||||||
else
|
else
|
||||||
# invite existing member to a topic
|
# invite existing member to a topic
|
||||||
user = User.find_by_username(username_or_email)
|
user = User.find_by_username(username_or_email)
|
||||||
@ -639,8 +639,8 @@ class Topic < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_by_email(invited_by, email, group_ids=nil)
|
def invite_by_email(invited_by, email, group_ids=nil, custom_message=nil)
|
||||||
Invite.invite_by_email(email, invited_by, self, group_ids)
|
Invite.invite_by_email(email, invited_by, self, group_ids, custom_message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_already_exists_for?(invite)
|
def email_already_exists_for?(invite)
|
||||||
|
@ -3043,10 +3043,10 @@ en:
|
|||||||
custom_message: "Make your invite a little bit more personal by writing a"
|
custom_message: "Make your invite a little bit more personal by writing a"
|
||||||
custom_message_link: "custom message"
|
custom_message_link: "custom message"
|
||||||
custom_message_placeholder: "Enter your custom message, use {invite_link} for specifying invite link."
|
custom_message_placeholder: "Enter your custom message, use {invite_link} for specifying invite link."
|
||||||
custom_message_template: |
|
custom_message_template_forum: |
|
||||||
Hello,
|
Hello,
|
||||||
|
|
||||||
You've been invited you to join
|
You've been invited to join
|
||||||
|
|
||||||
> **{site_title}**
|
> **{site_title}**
|
||||||
>
|
>
|
||||||
@ -3057,3 +3057,22 @@ en:
|
|||||||
{invite_link}
|
{invite_link}
|
||||||
|
|
||||||
This invitation is from a trusted user, so you won't need to log in.
|
This invitation is from a trusted user, so you won't need to log in.
|
||||||
|
|
||||||
|
custom_message_template_topic: |
|
||||||
|
Hello,
|
||||||
|
|
||||||
|
You've been invited to a discussion
|
||||||
|
|
||||||
|
> **{topic_title}**
|
||||||
|
>
|
||||||
|
> {topic_excerpt}
|
||||||
|
|
||||||
|
at
|
||||||
|
|
||||||
|
> {site_title} -- {site_description}
|
||||||
|
|
||||||
|
If you're interested, click the link below:
|
||||||
|
|
||||||
|
{invite_link}
|
||||||
|
|
||||||
|
This invitation is from a trusted user, so you can reply to the discussion immediately.
|
||||||
|
@ -74,7 +74,7 @@ describe InviteMailer do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "custom message does not include invite link" do
|
context "custom message does not include invite link" do
|
||||||
let(:custom_invite_without_link) { InviteMailer.send_invite(invite, "Hello,\n\nYou've been invited you to join\n\n> **{site_title}**\n>\n> {site_description}") }
|
let(:custom_invite_without_link) { InviteMailer.send_invite(invite, "Hello,\n\nYou've been invited to join\n\n> **{site_title}**\n>\n> {site_description}") }
|
||||||
|
|
||||||
it 'renders default body' do
|
it 'renders default body' do
|
||||||
expect(custom_invite_without_link.body).to be_present
|
expect(custom_invite_without_link.body).to be_present
|
||||||
@ -91,44 +91,67 @@ describe InviteMailer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
context "invite to topic" do
|
context "invite to topic" do
|
||||||
let(:topic) { Fabricate(:topic, excerpt: "Topic invite support is now available in Discourse!") }
|
let(:topic) { Fabricate(:topic, excerpt: "Topic invite support is now available in Discourse!") }
|
||||||
let(:invite) { topic.invite(topic.user, 'name@example.com') }
|
let(:invite) { topic.invite(topic.user, 'name@example.com') }
|
||||||
let(:invite_mail) { InviteMailer.send_invite(invite) }
|
|
||||||
|
|
||||||
it 'renders the invitee email' do
|
context "default invite message" do
|
||||||
expect(invite_mail.to).to eql(['name@example.com'])
|
let(:invite_mail) { InviteMailer.send_invite(invite) }
|
||||||
|
|
||||||
|
it 'renders the invitee email' do
|
||||||
|
expect(invite_mail.to).to eql(['name@example.com'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the subject' do
|
||||||
|
expect(invite_mail.subject).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders topic title in subject' do
|
||||||
|
expect(invite_mail.subject).to match(topic.title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders site domain name in subject' do
|
||||||
|
expect(invite_mail.subject).to match(Discourse.current_hostname)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the body' do
|
||||||
|
expect(invite_mail.body).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the inviter email' do
|
||||||
|
expect(invite_mail.from).to eql([SiteSetting.notification_email])
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders invite link' do
|
||||||
|
expect(invite_mail.body.encoded).to match("#{Discourse.base_url}/invites/#{invite.invite_key}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders topic title' do
|
||||||
|
expect(invite_mail.body.encoded).to match(topic.title)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the subject' do
|
context "custom invite message" do
|
||||||
expect(invite_mail.subject).to be_present
|
let(:custom_invite_mail) { InviteMailer.send_invite(invite, "Hello,\n\nYou've been invited to a discussion\n\n<a href=\"javascript:alert('HACK!')\">Click me.</a>\n\n> **{site_title}** -- {site_description}\n\nIf you're interested, click the link below:\n\n{invite_link}\n\nThis invitation is from a trusted user, so you can reply to the discussion immediately.") }
|
||||||
end
|
|
||||||
|
|
||||||
it 'renders topic title in subject' do
|
it 'renders the html' do
|
||||||
expect(invite_mail.subject).to match(topic.title)
|
expect(custom_invite_mail.html_part).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders site domain name in subject' do
|
it 'renders custom_message' do
|
||||||
expect(invite_mail.subject).to match(Discourse.current_hostname)
|
expect(custom_invite_mail.html_part.to_s).to match("You've been invited to a discussion")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the body' do
|
it 'sanitizes HTML' do
|
||||||
expect(invite_mail.body).to be_present
|
expect(custom_invite_mail.html_part.to_s).to_not match("HACK!")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the inviter email' do
|
it 'renders invite link' do
|
||||||
expect(invite_mail.from).to eql([SiteSetting.notification_email])
|
expect(custom_invite_mail.html_part.to_s).to match("#{Discourse.base_url}/invites/#{invite.invite_key}")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders invite link' do
|
|
||||||
expect(invite_mail.body.encoded).to match("#{Discourse.base_url}/invites/#{invite.invite_key}")
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'renders topic title' do
|
|
||||||
expect(invite_mail.body.encoded).to match(topic.title)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user