mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: invite existing user to a topic
This commit is contained in:
parent
586cca352d
commit
8c2d7dcaac
@ -1,47 +0,0 @@
|
|||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
|
||||||
import ObjectController from 'discourse/controllers/object';
|
|
||||||
|
|
||||||
export default ObjectController.extend(ModalFunctionality, {
|
|
||||||
modalClass: 'invite',
|
|
||||||
|
|
||||||
isAdmin: function(){
|
|
||||||
return Discourse.User.currentProp("admin");
|
|
||||||
}.property(),
|
|
||||||
|
|
||||||
onShow: function(){
|
|
||||||
this.set('controllers.modal.modalClass', 'invite-modal');
|
|
||||||
this.set('emailOrUsername', '');
|
|
||||||
},
|
|
||||||
|
|
||||||
disabled: function() {
|
|
||||||
if (this.get('saving')) return true;
|
|
||||||
return this.blank('emailOrUsername');
|
|
||||||
}.property('emailOrUsername', 'saving'),
|
|
||||||
|
|
||||||
buttonTitle: function() {
|
|
||||||
if (this.get('saving')) return I18n.t('topic.inviting');
|
|
||||||
return I18n.t('topic.invite_private.action');
|
|
||||||
}.property('saving'),
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
invite: function() {
|
|
||||||
if (this.get('disabled')) return;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.setProperties({saving: true, error: false});
|
|
||||||
|
|
||||||
// Invite the user to the private message
|
|
||||||
this.get('model').createInvite(this.get('emailOrUsername')).then(function(result) {
|
|
||||||
self.setProperties({saving: true, finished: true});
|
|
||||||
|
|
||||||
if(result && result.user) {
|
|
||||||
self.get('model.details.allowed_users').pushObject(result.user);
|
|
||||||
}
|
|
||||||
}).catch(function() {
|
|
||||||
self.setProperties({error: true, saving: false});
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
@ -6,7 +6,7 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
|
|
||||||
// If this isn't defined, it will proxy to the user model on the preferences
|
// If this isn't defined, it will proxy to the user model on the preferences
|
||||||
// page which is wrong.
|
// page which is wrong.
|
||||||
email: null,
|
emailOrUsername: null,
|
||||||
|
|
||||||
isAdmin: function(){
|
isAdmin: function(){
|
||||||
return Discourse.User.currentProp("admin");
|
return Discourse.User.currentProp("admin");
|
||||||
@ -19,12 +19,12 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
**/
|
**/
|
||||||
disabled: function() {
|
disabled: function() {
|
||||||
if (this.get('saving')) return true;
|
if (this.get('saving')) return true;
|
||||||
if (this.blank('email')) return true;
|
if (this.blank('emailOrUsername')) return true;
|
||||||
if (!Discourse.Utilities.emailValid(this.get('email'))) return true;
|
if ( !this.get('invitingToTopic') && !Discourse.Utilities.emailValid(this.get('emailOrUsername')) ) return true;
|
||||||
if (this.get('model.details.can_invite_to')) return false;
|
if (this.get('model.details.can_invite_to')) return false;
|
||||||
if (this.get('isPrivateTopic') && this.blank('groupNames')) return true;
|
if (this.get('isPrivateTopic') && this.blank('groupNames')) return true;
|
||||||
return false;
|
return false;
|
||||||
}.property('email', 'isPrivateTopic', 'groupNames', 'saving'),
|
}.property('emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'groupNames', 'saving'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The current text for the invite button
|
The current text for the invite button
|
||||||
@ -53,18 +53,45 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
**/
|
**/
|
||||||
isPrivateTopic: Em.computed.and('invitingToTopic', 'model.category.read_restricted'),
|
isPrivateTopic: Em.computed.and('invitingToTopic', 'model.category.read_restricted'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
Is Message?
|
||||||
|
|
||||||
|
@property isMessage
|
||||||
|
**/
|
||||||
|
isMessage: Em.computed.equal('model.archetype', 'private_message'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
Allow Existing Members? (username autocomplete)
|
||||||
|
|
||||||
|
@property allowExistingMembers
|
||||||
|
**/
|
||||||
|
allowExistingMembers: function() {
|
||||||
|
return this.get('invitingToTopic') && !this.get('isPrivateTopic');
|
||||||
|
}.property('invitingToTopic', 'isPrivateTopic'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
Show Groups? (add invited user to private group)
|
||||||
|
|
||||||
|
@property showGroups
|
||||||
|
**/
|
||||||
|
showGroups: function() {
|
||||||
|
return this.get('isAdmin') && (Discourse.Utilities.emailValid(this.get('emailOrUsername')) || this.get('isPrivateTopic') || !this.get('invitingToTopic'));
|
||||||
|
}.property('isAdmin', 'emailOrUsername', 'isPrivateTopic', 'invitingToTopic'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Instructional text for the modal.
|
Instructional text for the modal.
|
||||||
|
|
||||||
@property inviteInstructions
|
@property inviteInstructions
|
||||||
**/
|
**/
|
||||||
inviteInstructions: function() {
|
inviteInstructions: function() {
|
||||||
if (this.get('invitingToTopic')) {
|
if (this.get('isMessage')) {
|
||||||
|
return I18n.t('topic.invite_private.email_or_username');
|
||||||
|
} else if (this.get('invitingToTopic')) {
|
||||||
return I18n.t('topic.invite_reply.to_topic');
|
return I18n.t('topic.invite_reply.to_topic');
|
||||||
} else {
|
} else {
|
||||||
return I18n.t('topic.invite_reply.to_forum');
|
return I18n.t('topic.invite_reply.to_forum');
|
||||||
}
|
}
|
||||||
}.property('invitingToTopic'),
|
}.property('isMessage', 'invitingToTopic'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Instructional text for the group selection.
|
Instructional text for the group selection.
|
||||||
@ -92,8 +119,25 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
@property successMessage
|
@property successMessage
|
||||||
**/
|
**/
|
||||||
successMessage: function() {
|
successMessage: function() {
|
||||||
return I18n.t('topic.invite_reply.success', { email: this.get('email') });
|
if (this.get('isMessage')) {
|
||||||
}.property('email'),
|
return I18n.t('topic.invite_private.success');
|
||||||
|
} else {
|
||||||
|
return I18n.t('topic.invite_reply.success', { emailOrUsername: this.get('emailOrUsername') });
|
||||||
|
}
|
||||||
|
}.property('isMessage', 'emailOrUsername'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
The "error" text for when the invite fails.
|
||||||
|
|
||||||
|
@property errorMessage
|
||||||
|
**/
|
||||||
|
errorMessage: function() {
|
||||||
|
if (this.get('isMessage')) {
|
||||||
|
return I18n.t('topic.invite_private.error');
|
||||||
|
} else {
|
||||||
|
return I18n.t('topic.invite_reply.error');
|
||||||
|
}
|
||||||
|
}.property('isMessage'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reset the modal to allow a new user to be invited.
|
Reset the modal to allow a new user to be invited.
|
||||||
@ -102,7 +146,7 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
**/
|
**/
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
email: null,
|
emailOrUsername: null,
|
||||||
groupNames: null,
|
groupNames: null,
|
||||||
error: false,
|
error: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
@ -126,13 +170,15 @@ export default ObjectController.extend(ModalFunctionality, {
|
|||||||
var userInvitedController = this.get('controllers.user-invited');
|
var userInvitedController = this.get('controllers.user-invited');
|
||||||
|
|
||||||
this.setProperties({ saving: true, error: false });
|
this.setProperties({ saving: true, error: false });
|
||||||
this.get('model').createInvite(this.get('email'), groupNames).then(function() {
|
this.get('model').createInvite(this.get('emailOrUsername'), groupNames).then(function(result) {
|
||||||
self.setProperties({ saving: false, finished: true });
|
self.setProperties({ saving: false, finished: true });
|
||||||
if (!self.get('invitingToTopic')) {
|
if (!self.get('invitingToTopic')) {
|
||||||
Discourse.Invite.findInvitedBy(Discourse.User.current()).then(function (invite_model) {
|
Discourse.Invite.findInvitedBy(Discourse.User.current()).then(function (invite_model) {
|
||||||
userInvitedController.set('model', invite_model);
|
userInvitedController.set('model', invite_model);
|
||||||
userInvitedController.set('totalInvites', invite_model.invites.length);
|
userInvitedController.set('totalInvites', invite_model.invites.length);
|
||||||
});
|
});
|
||||||
|
} else if (self.get('isMessage') && result && result.user) {
|
||||||
|
self.get('model.details.allowed_users').pushObject(result.user);
|
||||||
}
|
}
|
||||||
}).catch(function() {
|
}).catch(function() {
|
||||||
self.setProperties({ saving: false, error: true });
|
self.setProperties({ saving: false, error: true });
|
||||||
|
@ -69,16 +69,6 @@ const TopicRoute = Discourse.Route.extend(ShowFooter, {
|
|||||||
this.controllerFor('invite').reset();
|
this.controllerFor('invite').reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
showPrivateInvite() {
|
|
||||||
showModal('invitePrivate', this.modelFor('topic'));
|
|
||||||
this.controllerFor('invitePrivate').setProperties({
|
|
||||||
email: null,
|
|
||||||
error: false,
|
|
||||||
saving: false,
|
|
||||||
finished: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
showHistory(post) {
|
showHistory(post) {
|
||||||
showModal('history', post);
|
showModal('history', post);
|
||||||
this.controllerFor('history').refresh(post.get("id"), "latest");
|
this.controllerFor('history').refresh(post.get("id"), "latest");
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{{#if error}}
|
{{#if error}}
|
||||||
<div class="alert alert-error">
|
<div class="alert alert-error">
|
||||||
<button class="close" data-dismiss="alert">×</button>
|
<button class="close" data-dismiss="alert">×</button>
|
||||||
{{i18n 'topic.invite_reply.error'}}
|
{{errorMessage}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
@ -11,9 +11,13 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
|
|
||||||
<label>{{inviteInstructions}}</label>
|
<label>{{inviteInstructions}}</label>
|
||||||
{{text-field value=email placeholderKey="topic.invite_reply.email_placeholder"}}
|
{{#if allowExistingMembers}}
|
||||||
|
{{user-selector single="true" allowAny=true usernames=emailOrUsername includeGroups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||||
|
{{else}}
|
||||||
|
{{text-field value=emailOrUsername placeholderKey="topic.invite_reply.email_placeholder"}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if isAdmin}}
|
{{#if showGroups}}
|
||||||
<label>{{{groupInstructions}}}</label>
|
<label>{{{groupInstructions}}}</label>
|
||||||
{{group-selector groupFinder=groupFinder groupNames=groupNames placeholderKey="topic.invite_private.group_name"}}
|
{{group-selector groupFinder=groupFinder groupNames=groupNames placeholderKey="topic.invite_private.group_name"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
<div class="modal-body">
|
|
||||||
{{#if error}}
|
|
||||||
<div class="alert alert-error">
|
|
||||||
<button class="close" data-dismiss="alert">×</button>
|
|
||||||
{{i18n 'topic.invite_private.error'}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if finished}}
|
|
||||||
{{i18n 'topic.invite_private.success'}}
|
|
||||||
{{else}}
|
|
||||||
<label>{{i18n 'topic.invite_private.email_or_username'}}</label>
|
|
||||||
{{user-selector single="true" allowAny=true usernames=emailOrUsername includeGroups="true" placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
{{#if finished}}
|
|
||||||
<button class='btn btn-primary' {{action "closeModal"}}>{{i18n 'close'}}</button>
|
|
||||||
{{else}}
|
|
||||||
<button class='btn btn-primary' {{bind-attr disabled="disabled"}} {{action "invite"}}>{{buttonTitle}}</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
</div>
|
|
@ -1,6 +0,0 @@
|
|||||||
import ModalBodyView from "discourse/views/modal-body";
|
|
||||||
|
|
||||||
export default ModalBodyView.extend({
|
|
||||||
templateName: 'modal/invite_private',
|
|
||||||
title: I18n.t('topic.invite_private.title')
|
|
||||||
});
|
|
@ -4,9 +4,13 @@ export default ModalBodyView.extend({
|
|||||||
templateName: 'modal/invite',
|
templateName: 'modal/invite',
|
||||||
|
|
||||||
title: function() {
|
title: function() {
|
||||||
return this.get('controller.invitingToTopic') ?
|
if (this.get('controller.isMessage')) {
|
||||||
I18n.t('topic.invite_reply.title') :
|
return I18n.t('topic.invite_private.title');
|
||||||
I18n.t('user.invited.create');
|
} else if (this.get('controller.invitingToTopic')) {
|
||||||
}.property('controller.invitingToTopic')
|
return I18n.t('topic.invite_reply.title');
|
||||||
|
} else {
|
||||||
|
return I18n.t('user.invited.create');
|
||||||
|
}
|
||||||
|
}.property('controller.{invitingToTopic,isMessage}')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -51,8 +51,7 @@ export default DiscourseContainerView.extend({
|
|||||||
|
|
||||||
// If we have a private message
|
// If we have a private message
|
||||||
if (this.get('topic.isPrivateMessage')) {
|
if (this.get('topic.isPrivateMessage')) {
|
||||||
container.attachViewWithArgs({ topic: topic, showPrivateInviteAction: 'showPrivateInvite' }, PrivateMessageMapComponent);
|
container.attachViewWithArgs({ topic: topic, showPrivateInviteAction: 'showInvite' }, PrivateMessageMapComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,6 +124,11 @@ class UserNotifications < ActionMailer::Base
|
|||||||
notification_email(user, opts)
|
notification_email(user, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_invited_to_topic(user, opts)
|
||||||
|
opts[:show_category_in_subject] = true
|
||||||
|
notification_email(user, opts)
|
||||||
|
end
|
||||||
|
|
||||||
def mailing_list_notify(user, post)
|
def mailing_list_notify(user, post)
|
||||||
send_notification_email(
|
send_notification_email(
|
||||||
title: post.topic.title,
|
title: post.topic.title,
|
||||||
@ -188,11 +193,12 @@ class UserNotifications < ActionMailer::Base
|
|||||||
use_site_subject = opts[:use_site_subject]
|
use_site_subject = opts[:use_site_subject]
|
||||||
add_re_to_subject = opts[:add_re_to_subject]
|
add_re_to_subject = opts[:add_re_to_subject]
|
||||||
show_category_in_subject = opts[:show_category_in_subject]
|
show_category_in_subject = opts[:show_category_in_subject]
|
||||||
|
original_username = @notification.data_hash[:original_username] || @notification.data_hash[:display_username]
|
||||||
|
|
||||||
send_notification_email(
|
send_notification_email(
|
||||||
title: title,
|
title: title,
|
||||||
post: @post,
|
post: @post,
|
||||||
username: @notification.data_hash[:original_username],
|
username: original_username,
|
||||||
from_alias: user_name,
|
from_alias: user_name,
|
||||||
allow_reply_by_email: allow_reply_by_email,
|
allow_reply_by_email: allow_reply_by_email,
|
||||||
use_site_subject: use_site_subject,
|
use_site_subject: use_site_subject,
|
||||||
|
@ -31,7 +31,7 @@ class Notification < ActiveRecord::Base
|
|||||||
@types ||= Enum.new(
|
@types ||= Enum.new(
|
||||||
:mentioned, :replied, :quoted, :edited, :liked, :private_message,
|
:mentioned, :replied, :quoted, :edited, :liked, :private_message,
|
||||||
:invited_to_private_message, :invitee_accepted, :posted, :moved_post,
|
:invited_to_private_message, :invitee_accepted, :posted, :moved_post,
|
||||||
:linked, :granted_badge
|
:linked, :granted_badge, :invited_to_topic
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ class Topic < ActiveRecord::Base
|
|||||||
# 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)
|
||||||
if private_message?
|
if private_message?
|
||||||
# If the user exists, add them to the topic.
|
# 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)
|
||||||
if user && topic_allowed_users.create!(user_id: user.id)
|
if user && topic_allowed_users.create!(user_id: user.id)
|
||||||
|
|
||||||
@ -555,7 +555,20 @@ class Topic < ActiveRecord::Base
|
|||||||
# 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)
|
||||||
else
|
else
|
||||||
false
|
# invite existing member to a topic
|
||||||
|
user = User.find_by_username_or_email(username_or_email)
|
||||||
|
if user && topic_allowed_users.create!(user_id: user.id)
|
||||||
|
|
||||||
|
# Notify the user they've been invited
|
||||||
|
user.notifications.create(notification_type: Notification.types[:invited_to_topic],
|
||||||
|
topic_id: id,
|
||||||
|
post_number: 1,
|
||||||
|
data: { topic_title: title,
|
||||||
|
display_username: invited_by.username }.to_json)
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ class UserEmailObserver < ActiveRecord::Observer
|
|||||||
enqueue :user_invited_to_private_message
|
enqueue :user_invited_to_private_message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def invited_to_topic
|
||||||
|
enqueue :user_invited_to_topic
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def enqueue(type)
|
def enqueue(type)
|
||||||
|
@ -481,7 +481,7 @@ en:
|
|||||||
weekly: "weekly"
|
weekly: "weekly"
|
||||||
every_two_weeks: "every two weeks"
|
every_two_weeks: "every two weeks"
|
||||||
|
|
||||||
email_direct: "Send me an email when someone quotes me, replies to my post, or mentions my @username"
|
email_direct: "Send me an email when someone quotes me, replies to my post, or mentions my @username or invites me to a topic"
|
||||||
email_private_messages: "Send me an email when someone messages me"
|
email_private_messages: "Send me an email when someone messages me"
|
||||||
email_always: "Do not suppress email notifications when I am active on the site"
|
email_always: "Do not suppress email notifications when I am active on the site"
|
||||||
|
|
||||||
@ -786,6 +786,7 @@ en:
|
|||||||
liked: "<i title='liked' class='fa fa-heart'></i><p><span>{{username}}</span> {{description}}</p>"
|
liked: "<i title='liked' class='fa fa-heart'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
private_message: "<i title='private message' class='fa fa-envelope-o'></i><p><span>{{username}}</span> {{description}}</p>"
|
private_message: "<i title='private message' class='fa fa-envelope-o'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
invited_to_private_message: "<i title='private message' class='fa fa-envelope-o'></i><p><span>{{username}}</span> {{description}}</p>"
|
invited_to_private_message: "<i title='private message' class='fa fa-envelope-o'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
|
invited_to_topic: "<i title='invited to topic' class='fa fa-envelope-o'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
invitee_accepted: "<i title='accepted your invitation' class='fa fa-user'></i><p><span>{{username}}</span> accepted your invitation</p>"
|
invitee_accepted: "<i title='accepted your invitation' class='fa fa-user'></i><p><span>{{username}}</span> accepted your invitation</p>"
|
||||||
moved_post: "<i title='moved post' class='fa fa-sign-out'></i><p><span>{{username}}</span> moved {{description}}</p>"
|
moved_post: "<i title='moved post' class='fa fa-sign-out'></i><p><span>{{username}}</span> moved {{description}}</p>"
|
||||||
linked: "<i title='linked post' class='fa fa-arrow-left'></i><p><span>{{username}}</span> {{description}}</p>"
|
linked: "<i title='linked post' class='fa fa-arrow-left'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
@ -1067,14 +1068,14 @@ en:
|
|||||||
|
|
||||||
invite_reply:
|
invite_reply:
|
||||||
title: 'Invite'
|
title: 'Invite'
|
||||||
action: 'Email Invite'
|
action: 'Send Invite'
|
||||||
help: 'send invitations to friends so they can reply to this topic with a single click'
|
help: 'send invitations to friends so they can reply to this topic with a single click'
|
||||||
to_topic: "We'll send a brief email allowing your friend to immediately join and reply to this topic by clicking a link, no login required."
|
to_topic: "We'll send a brief email allowing your friend to immediately join and reply to this topic by clicking a link, no login required."
|
||||||
to_forum: "We'll send a brief email allowing your friend to immediately join by clicking a link, no login required."
|
to_forum: "We'll send a brief email allowing your friend to immediately join by clicking a link, no login required."
|
||||||
|
|
||||||
email_placeholder: 'name@example.com'
|
email_placeholder: 'name@example.com'
|
||||||
success: "We mailed out an invitation to <b>{{email}}</b>. We'll notify you when the invitation is redeemed. Check the invitations tab on your user page to keep track of your invites."
|
success: "We mailed out an invitation to <b>{{emailOrUsername}}</b>. We'll notify you when the invitation is redeemed. Check the invitations tab on your user page to keep track of your invites."
|
||||||
error: "Sorry, we couldn't invite that person. Perhaps they are already a user? (Invites are rate limited)"
|
error: "Sorry, we couldn't invite that person. Perhaps they have already been invited? (Invites are rate limited)"
|
||||||
|
|
||||||
login_reply: 'Log In to Reply'
|
login_reply: 'Log In to Reply'
|
||||||
|
|
||||||
|
@ -1157,6 +1157,7 @@ en:
|
|||||||
moved_post: "%{display_username} moved your post to %{link}"
|
moved_post: "%{display_username} moved your post to %{link}"
|
||||||
private_message: "%{display_username} sent you a message: %{link}"
|
private_message: "%{display_username} sent you a message: %{link}"
|
||||||
invited_to_private_message: "%{display_username} invited you to a message: %{link}"
|
invited_to_private_message: "%{display_username} invited you to a message: %{link}"
|
||||||
|
invited_to_topic: "%{display_username} invited you to a topic: %{link}"
|
||||||
invitee_accepted: "%{display_username} accepted your invitation"
|
invitee_accepted: "%{display_username} accepted your invitation"
|
||||||
linked: "%{display_username} linked you in %{link}"
|
linked: "%{display_username} linked you in %{link}"
|
||||||
granted_badge: "You earned %{link}"
|
granted_badge: "You earned %{link}"
|
||||||
@ -1772,6 +1773,13 @@ en:
|
|||||||
|
|
||||||
Please visit this link to view the topic: %{base_url}%{url}
|
Please visit this link to view the topic: %{base_url}%{url}
|
||||||
|
|
||||||
|
user_invited_to_topic:
|
||||||
|
subject_template: "[%{site_name}] %{username} invited you to a topic '%{topic_title}'"
|
||||||
|
text_body_template: |
|
||||||
|
%{username} invited you to a topic '%{topic_title}' on %{site_name}:
|
||||||
|
|
||||||
|
Please visit this link to view the topic: %{base_url}%{url}
|
||||||
|
|
||||||
user_replied:
|
user_replied:
|
||||||
subject_template: "[%{site_name}] %{topic_title}"
|
subject_template: "[%{site_name}] %{topic_title}"
|
||||||
text_body_template: |
|
text_body_template: |
|
||||||
|
@ -326,4 +326,11 @@ describe UserNotifications do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "user invited to a topic" do
|
||||||
|
include_examples "notification email building" do
|
||||||
|
let(:notification_type) { :invited_to_topic }
|
||||||
|
include_examples "no reply by email"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -98,4 +98,22 @@ describe UserEmailObserver do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'user_invited_to_topic' do
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
let!(:notification) { Fabricate(:notification, user: user, notification_type: 13) }
|
||||||
|
|
||||||
|
it "enqueues a job for the email" do
|
||||||
|
Jobs.expects(:enqueue_in).with(SiteSetting.email_time_window_mins.minutes, :user_email, type: :user_invited_to_topic, user_id: notification.user_id, notification_id: notification.id)
|
||||||
|
UserEmailObserver.send(:new).after_commit(notification)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't enqueue an email if the user has mention emails disabled" do
|
||||||
|
user.expects(:email_direct?).returns(false)
|
||||||
|
Jobs.expects(:enqueue_in).with(SiteSetting.email_time_window_mins.minutes, :user_email, has_entry(type: :user_invited_to_topic)).never
|
||||||
|
UserEmailObserver.send(:new).after_commit(notification)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user