parent
112f2e6187
commit
d66c83364c
@ -1,14 +0,0 @@ |
||||
Meteor.startup -> |
||||
RocketChat.ChannelSettings.addOption |
||||
group: ['room'] |
||||
id: 'mail-messages' |
||||
template: 'channelSettingsMailMessages' |
||||
validation: -> |
||||
return RocketChat.authz.hasAllPermission('mail-messages') |
||||
|
||||
RocketChat.callbacks.add 'roomExit', (mainNode) -> |
||||
messagesBox = $('.messages-box') |
||||
if messagesBox.get(0)? |
||||
instance = Blaze.getView(messagesBox.get(0))?.templateInstance() |
||||
instance?.resetSelection(false) |
||||
, RocketChat.callbacks.priority.MEDIUM, 'room-exit-mail-messages' |
||||
@ -0,0 +1,12 @@ |
||||
import resetSelection from '../resetSelection'; |
||||
Meteor.startup(() => { |
||||
RocketChat.ChannelSettings.addOption({ |
||||
group: ['room'], |
||||
id: 'mail-messages', |
||||
template: 'channelSettingsMailMessages', |
||||
validation() { |
||||
return RocketChat.authz.hasAllPermission('mail-messages'); |
||||
} |
||||
}); |
||||
RocketChat.callbacks.add('roomExit', () => resetSelection(false), RocketChat.callbacks.priority.MEDIUM, 'room-exit-mail-messages'); |
||||
}); |
||||
@ -0,0 +1,11 @@ |
||||
export default function resetSelection(reset) { |
||||
const [el] = $('.messages-box'); |
||||
if (!el) { |
||||
return; |
||||
} |
||||
const view = Blaze.getView(el); |
||||
if (view && typeof view.templateInstance === 'function') { |
||||
const {resetSelection} = view.templateInstance(); |
||||
typeof resetSelection === 'function' && resetSelection(reset); |
||||
} |
||||
} |
||||
@ -1,14 +0,0 @@ |
||||
Template.channelSettingsMailMessages.helpers |
||||
canSendEmail: -> |
||||
return FlowRouter.getRouteName() isnt 'admin-rooms' |
||||
|
||||
Template.channelSettingsMailMessages.events |
||||
'click button.mail-messages': (e, t) -> |
||||
Session.set 'channelSettingsMailMessages', Session.get('openedRoom') |
||||
@tabBar.setTemplate('mailMessagesInstructions') |
||||
view = Blaze.getView($('.messages-box')[0]) |
||||
view?.templateInstance?().resetSelection?(true) |
||||
|
||||
Template.channelSettingsMailMessages.onCreated -> |
||||
view = Blaze.getView($('.messages-box')[0]) |
||||
view?.templateInstance?().resetSelection?(false) |
||||
@ -0,0 +1,17 @@ |
||||
import resetSelection from '../resetSelection'; |
||||
|
||||
Template.channelSettingsMailMessages.helpers({ |
||||
canSendEmail() { |
||||
return FlowRouter.getRouteName() !== 'admin-rooms'; |
||||
} |
||||
}); |
||||
|
||||
Template.channelSettingsMailMessages.events({ |
||||
'click button.mail-messages'() { |
||||
Session.set('channelSettingsMailMessages', Session.get('openedRoom')); |
||||
this.tabBar.setTemplate('mailMessagesInstructions'); |
||||
resetSelection(true); |
||||
} |
||||
}); |
||||
|
||||
Template.channelSettingsMailMessages.onCreated(() =>resetSelection(false)); |
||||
@ -1,126 +0,0 @@ |
||||
import toastr from 'toastr' |
||||
Template.mailMessagesInstructions.helpers |
||||
name: -> |
||||
return Meteor.user().name |
||||
email: -> |
||||
return Meteor.user().emails?[0]?.address |
||||
roomName: -> |
||||
return ChatRoom.findOne(Session.get('openedRoom'))?.name |
||||
erroredEmails: -> |
||||
return Template.instance()?.erroredEmails.get().join(', ') |
||||
autocompleteSettings: -> |
||||
return { |
||||
limit: 10 |
||||
# inputDelay: 300 |
||||
rules: [ |
||||
{ |
||||
# @TODO maybe change this 'collection' and/or template |
||||
collection: 'CachedChannelList' |
||||
subscription: 'userAutocomplete' |
||||
field: 'username' |
||||
template: Template.userSearch |
||||
noMatchTemplate: Template.userSearchEmpty |
||||
matchAll: true |
||||
filter: |
||||
exceptions: Template.instance().selectedUsers.get() |
||||
selector: (match) -> |
||||
return { term: match } |
||||
sort: 'username' |
||||
} |
||||
] |
||||
} |
||||
selectedUsers: -> |
||||
return Template.instance().selectedUsers.get() |
||||
|
||||
Template.mailMessagesInstructions.events |
||||
'click .cancel': (e, t) -> |
||||
t.reset() |
||||
|
||||
'click .send': (e, t) -> |
||||
t.$('.error').hide() |
||||
$btn = t.$('button.send') |
||||
oldBtnValue = $btn.html() |
||||
$btn.html(TAPi18n.__('Sending')) |
||||
|
||||
selectedMessages = $('.messages-box .message.selected') |
||||
|
||||
error = false |
||||
if selectedMessages.length is 0 |
||||
t.$('.error-select').show() |
||||
error = true |
||||
|
||||
if t.$('input[name=to_emails]').val().trim() |
||||
rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/ |
||||
emails = t.$('input[name=to_emails]').val().trim().split(',') |
||||
erroredEmails = [] |
||||
for email in emails |
||||
unless rfcMailPatternWithName.test email.trim() |
||||
erroredEmails.push email.trim() |
||||
|
||||
t.erroredEmails.set erroredEmails |
||||
if erroredEmails.length > 0 |
||||
t.$('.error-invalid-emails').show() |
||||
error = true |
||||
else if not t.selectedUsers.get().length |
||||
t.$('.error-missing-to').show() |
||||
error = true |
||||
|
||||
if error |
||||
$btn.html(oldBtnValue) |
||||
else |
||||
data = |
||||
rid: Session.get('openedRoom') |
||||
to_users: t.selectedUsers.get() |
||||
to_emails: t.$('input[name=to_emails]').val().trim() |
||||
subject: t.$('input[name=subject]').val().trim() |
||||
messages: selectedMessages.map((i, message) -> return message.id).toArray() |
||||
language: localStorage.getItem('userLanguage') |
||||
|
||||
Meteor.call 'mailMessages', data, (err, result) -> |
||||
$btn.html(oldBtnValue) |
||||
if err? |
||||
return handleError(err) |
||||
|
||||
console.log(result) |
||||
toastr.success(TAPi18n.__('Your_email_has_been_queued_for_sending')) |
||||
t.reset() |
||||
|
||||
'click .select-all': (e, t) -> |
||||
t.$('.error-select').hide() |
||||
|
||||
view = Blaze.getView($('.messages-box')[0]) |
||||
view?.templateInstance?().selectedMessages = _.pluck(ChatMessage.find({rid: Session.get('openedRoom')})?.fetch(), '_id') |
||||
$(".messages-box .message").addClass('selected') |
||||
|
||||
'autocompleteselect #to_users': (event, instance, doc) -> |
||||
instance.selectedUsers.set instance.selectedUsers.get().concat doc.username |
||||
event.currentTarget.value = '' |
||||
event.currentTarget.focus() |
||||
|
||||
'click .remove-to-user': (e, instance) -> |
||||
self = @ |
||||
|
||||
users = Template.instance().selectedUsers.get() |
||||
users = _.reject Template.instance().selectedUsers.get(), (_id) -> |
||||
return _id is self.valueOf() |
||||
|
||||
Template.instance().selectedUsers.set(users) |
||||
|
||||
$('#to_users').focus() |
||||
|
||||
Template.mailMessagesInstructions.onCreated -> |
||||
@autoCompleteCollection = new Mongo.Collection null |
||||
@selectedUsers = new ReactiveVar [] |
||||
@erroredEmails = new ReactiveVar [] |
||||
|
||||
currentData = Template.currentData() |
||||
|
||||
@reset = => |
||||
@selectedUsers.set [] |
||||
currentData.tabBar.setTemplate('channelSettings') |
||||
view = Blaze.getView($('.messages-box')[0]) |
||||
view?.templateInstance?().resetSelection?(false) |
||||
|
||||
@autorun => |
||||
if Session.get('channelSettingsMailMessages') isnt Session.get('openedRoom') |
||||
this.reset() |
||||
@ -0,0 +1,148 @@ |
||||
import toastr from 'toastr'; |
||||
import resetSelection from '../resetSelection'; |
||||
Template.mailMessagesInstructions.helpers({ |
||||
name() { |
||||
return Meteor.user().name; |
||||
}, |
||||
email() { |
||||
const {emails} = Meteor.user(); |
||||
return emails && emails[0].address; |
||||
}, |
||||
roomName() { |
||||
const room = ChatRoom.findOne(Session.get('openedRoom')); |
||||
return room && room.name; |
||||
}, |
||||
erroredEmails() { |
||||
const instance = Template.instance(); |
||||
return instance && instance.erroredEmails.get().join(', '); |
||||
}, |
||||
autocompleteSettings() { |
||||
return { |
||||
limit: 10, |
||||
rules: [ |
||||
{ |
||||
collection: 'CachedChannelList', |
||||
subscription: 'userAutocomplete', |
||||
field: 'username', |
||||
template: Template.userSearch, |
||||
noMatchTemplate: Template.userSearchEmpty, |
||||
matchAll: true, |
||||
filter: { |
||||
exceptions: Template.instance().selectedUsers.get() |
||||
}, |
||||
selector(match) { |
||||
return { |
||||
term: match |
||||
}; |
||||
}, |
||||
sort: 'username' |
||||
} |
||||
] |
||||
}; |
||||
}, |
||||
selectedUsers() { |
||||
return Template.instance().selectedUsers.get(); |
||||
} |
||||
}); |
||||
|
||||
Template.mailMessagesInstructions.events({ |
||||
'click .cancel'(e, t) { |
||||
return t.reset(); |
||||
}, |
||||
'click .send'(e, t) { |
||||
t.$('.error').hide(); |
||||
const $btn = t.$('button.send'); |
||||
const oldBtnValue = $btn.html(); |
||||
$btn.html(TAPi18n.__('Sending')); |
||||
const selectedMessages = $('.messages-box .message.selected'); |
||||
let error = false; |
||||
if (selectedMessages.length === 0) { |
||||
t.$('.error-select').show(); |
||||
error = true; |
||||
} |
||||
if (t.$('input[name=to_emails]').val().trim()) { |
||||
const rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/; |
||||
const emails = t.$('input[name=to_emails]').val().trim().split(','); |
||||
const erroredEmails = []; |
||||
for (let j = 0, len = emails.length; j < len; j++) { |
||||
const email = emails[j]; |
||||
if (!rfcMailPatternWithName.test(email.trim())) { |
||||
erroredEmails.push(email.trim()); |
||||
} |
||||
} |
||||
t.erroredEmails.set(erroredEmails); |
||||
if (erroredEmails.length > 0) { |
||||
t.$('.error-invalid-emails').show(); |
||||
error = true; |
||||
} |
||||
} else if (!t.selectedUsers.get().length) { |
||||
t.$('.error-missing-to').show(); |
||||
error = true; |
||||
} |
||||
if (error) { |
||||
return $btn.html(oldBtnValue); |
||||
} |
||||
const data = { |
||||
rid: Session.get('openedRoom'), |
||||
to_users: t.selectedUsers.get(), |
||||
to_emails: t.$('input[name=to_emails]').val().trim(), |
||||
subject: t.$('input[name=subject]').val().trim(), |
||||
messages: selectedMessages.map(function(i, message) { |
||||
return message.id; |
||||
}).toArray(), |
||||
language: localStorage.getItem('userLanguage') |
||||
}; |
||||
return Meteor.call('mailMessages', data, function(err, result) { |
||||
$btn.html(oldBtnValue); |
||||
if (err != null) { |
||||
return handleError(err); |
||||
} |
||||
console.log(result); |
||||
toastr.success(TAPi18n.__('Your_email_has_been_queued_for_sending')); |
||||
return t.reset(); |
||||
}); |
||||
}, |
||||
'click .select-all'(e, t) { |
||||
t.$('.error-select').hide(); |
||||
const view = Blaze.getView($('.messages-box')[0]); |
||||
if (view != null) { |
||||
if (typeof view.templateInstance === 'function') { |
||||
const chat = ChatMessage.find({ |
||||
rid: Session.get('openedRoom') |
||||
}); |
||||
view.templateInstance().selectedMessages = _.pluck(chat && chat.fetch(), '_id'); |
||||
} |
||||
} |
||||
return $('.messages-box .message').addClass('selected'); |
||||
}, |
||||
'autocompleteselect #to_users'(event, instance, doc) { |
||||
instance.selectedUsers.set(instance.selectedUsers.get().concat(doc.username)); |
||||
event.currentTarget.value = ''; |
||||
return event.currentTarget.focus(); |
||||
}, |
||||
'click .remove-to-user'() { |
||||
let users = Template.instance().selectedUsers.get(); |
||||
users = _.reject(Template.instance().selectedUsers.get(), (_id) => { |
||||
return _id === this.valueOf(); |
||||
}); |
||||
Template.instance().selectedUsers.set(users); |
||||
return $('#to_users').focus(); |
||||
} |
||||
}); |
||||
|
||||
Template.mailMessagesInstructions.onCreated(function() { |
||||
const currentData = Template.currentData(); |
||||
this.autoCompleteCollection = new Mongo.Collection(null); |
||||
this.selectedUsers = new ReactiveVar([]); |
||||
this.erroredEmails = new ReactiveVar([]); |
||||
this.reset = () => { |
||||
this.selectedUsers.set([]); |
||||
currentData.tabBar.setTemplate('channelSettings'); |
||||
resetSelection(false); |
||||
}; |
||||
return this.autorun(() => { |
||||
if (Session.get('channelSettingsMailMessages') !== Session.get('openedRoom')) { |
||||
return this.reset(); |
||||
} |
||||
}); |
||||
}); |
||||
@ -1,3 +0,0 @@ |
||||
Meteor.startup -> |
||||
permission = { _id: 'mail-messages', roles : [ 'admin' ] } |
||||
RocketChat.models.Permissions.upsert( permission._id, { $setOnInsert : permission }) |
||||
@ -0,0 +1,9 @@ |
||||
Meteor.startup(function() { |
||||
const permission = { |
||||
_id: 'mail-messages', |
||||
roles: ['admin'] |
||||
}; |
||||
return RocketChat.models.Permissions.upsert(permission._id, { |
||||
$setOnInsert: permission |
||||
}); |
||||
}); |
||||
@ -1,65 +0,0 @@ |
||||
import moment from 'moment' |
||||
|
||||
Meteor.methods |
||||
'mailMessages': (data) -> |
||||
if not Meteor.userId() |
||||
throw new Meteor.Error('error-invalid-user', "Invalid user", { method: 'mailMessages' }) |
||||
|
||||
check(data, Match.ObjectIncluding({ rid: String, to_users: [ String ], to_emails: String, subject: String, messages: [ String ], language: String })) |
||||
|
||||
room = Meteor.call 'canAccessRoom', data.rid, Meteor.userId() |
||||
unless room |
||||
throw new Meteor.Error('error-invalid-room', "Invalid room", { method: 'mailMessages' }) |
||||
|
||||
unless RocketChat.authz.hasPermission(Meteor.userId(), 'mail-messages') |
||||
throw new Meteor.Error 'error-action-not-allowed', 'Mailing is not allowed', { method: 'mailMessages', action: 'Mailing' } |
||||
|
||||
rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/ |
||||
|
||||
emails = _.compact(data.to_emails.trim().split(',')) |
||||
missing = [] |
||||
if data.to_users.length > 0 |
||||
for username in data.to_users |
||||
user = RocketChat.models.Users.findOneByUsername(username) |
||||
if user?.emails?[0]?.address |
||||
emails.push user.emails[0].address |
||||
else |
||||
missing.push username |
||||
|
||||
console.log 'Sending messages to e-mails: ', emails |
||||
|
||||
for email in emails |
||||
unless rfcMailPatternWithName.test email.trim() |
||||
throw new Meteor.Error('error-invalid-email', "Invalid email #{email}", { method: 'mailMessages', email: email }) |
||||
|
||||
user = Meteor.user() |
||||
name = user.name |
||||
email = user.emails?[0]?.address |
||||
|
||||
data.language = data.language.split('-').shift().toLowerCase() |
||||
|
||||
if data.language isnt 'en' |
||||
localeFn = Meteor.call 'loadLocale', data.language |
||||
if localeFn |
||||
Function(localeFn)() |
||||
|
||||
html = "" |
||||
|
||||
header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || "") |
||||
footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || "") |
||||
|
||||
RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) -> |
||||
dateTime = moment(message.ts).locale(data.language).format('L LT') |
||||
html += "<p style='margin-bottom: 5px'><b>#{message.u.username}</b> <span style='color: #aaa; font-size: 12px'>#{dateTime}</span><br />" + RocketChat.Message.parse(message, data.language) + "</p>" |
||||
|
||||
Meteor.defer -> |
||||
Email.send |
||||
to: emails |
||||
from: RocketChat.settings.get('From_Email') |
||||
replyTo: email |
||||
subject: data.subject |
||||
html: header + html + footer |
||||
|
||||
console.log 'Sending email to ' + emails.join(', ') |
||||
|
||||
return { success: true, missing: missing } |
||||
@ -0,0 +1,86 @@ |
||||
import moment from 'moment'; |
||||
|
||||
Meteor.methods({ |
||||
'mailMessages'(data) { |
||||
if (!Meteor.userId()) { |
||||
throw new Meteor.Error('error-invalid-user', 'Invalid user', { |
||||
method: 'mailMessages' |
||||
}); |
||||
} |
||||
check(data, Match.ObjectIncluding({ |
||||
rid: String, |
||||
to_users: [String], |
||||
to_emails: String, |
||||
subject: String, |
||||
messages: [String], |
||||
language: String |
||||
})); |
||||
const room = Meteor.call('canAccessRoom', data.rid, Meteor.userId()); |
||||
if (!room) { |
||||
throw new Meteor.Error('error-invalid-room', 'Invalid room', { |
||||
method: 'mailMessages' |
||||
}); |
||||
} |
||||
if (!RocketChat.authz.hasPermission(Meteor.userId(), 'mail-messages')) { |
||||
throw new Meteor.Error('error-action-not-allowed', 'Mailing is not allowed', { |
||||
method: 'mailMessages', |
||||
action: 'Mailing' |
||||
}); |
||||
} |
||||
const rfcMailPatternWithName = /^(?:.*<)?([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?:>?)$/; |
||||
const emails = _.compact(data.to_emails.trim().split(',')); |
||||
const missing = []; |
||||
if (data.to_users.length > 0) { |
||||
_.each(data.to_users, (username) => { |
||||
const user = RocketChat.models.Users.findOneByUsername(username); |
||||
if (user && user.emails && user.emails[0].address) { |
||||
emails.push(user.emails[0].address); |
||||
} else { |
||||
missing.push(username); |
||||
} |
||||
}); |
||||
} |
||||
console.log('Sending messages to e-mails: ', emails); |
||||
_.each(emails, (email) => { |
||||
if (!rfcMailPatternWithName.test(email.trim())) { |
||||
throw new Meteor.Error('error-invalid-email', `Invalid email ${ email }`, { |
||||
method: 'mailMessages', |
||||
email |
||||
}); |
||||
} |
||||
}); |
||||
const user = Meteor.user(); |
||||
const email = user.emails && user.emails[0] && user.emails[0].address; |
||||
data.language = data.language.split('-').shift().toLowerCase(); |
||||
if (data.language !== 'en') { |
||||
const localeFn = Meteor.call('loadLocale', data.language); |
||||
if (localeFn) { |
||||
Function(localeFn)(); |
||||
} |
||||
} |
||||
|
||||
const header = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Header') || ''); |
||||
const footer = RocketChat.placeholders.replace(RocketChat.settings.get('Email_Footer') || ''); |
||||
const html = RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { |
||||
sort: { ts: 1 } |
||||
}).map(function(message) { |
||||
const dateTime = moment(message.ts).locale(data.language).format('L LT'); |
||||
return `<p style='margin-bottom: 5px'><b>${ message.u.username }</b> <span style='color: #aaa; font-size: 12px'>${ dateTime }</span><br />${ RocketChat.Message.parse(message, data.language) }</p>`; |
||||
}).join(''); |
||||
|
||||
Meteor.defer(function() { |
||||
Email.send({ |
||||
to: emails, |
||||
from: RocketChat.settings.get('From_Email'), |
||||
replyTo: email, |
||||
subject: data.subject, |
||||
html: header + html + footer |
||||
}); |
||||
return console.log(`Sending email to ${ emails.join(', ') }`); |
||||
}); |
||||
return { |
||||
success: true, |
||||
missing |
||||
}; |
||||
} |
||||
}); |
||||
Loading…
Reference in new issue