package converted

pull/6541/head
Guilherme Gazzo 9 years ago
parent 112f2e6187
commit d66c83364c
  1. 14
      packages/rocketchat-channel-settings-mail-messages/client/lib/startup.coffee
  2. 12
      packages/rocketchat-channel-settings-mail-messages/client/lib/startup.js
  3. 11
      packages/rocketchat-channel-settings-mail-messages/client/resetSelection.js
  4. 14
      packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.coffee
  5. 17
      packages/rocketchat-channel-settings-mail-messages/client/views/channelSettingsMailMessages.js
  6. 126
      packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.coffee
  7. 148
      packages/rocketchat-channel-settings-mail-messages/client/views/mailMessagesInstructions.js
  8. 11
      packages/rocketchat-channel-settings-mail-messages/package.js
  9. 3
      packages/rocketchat-channel-settings-mail-messages/server/lib/startup.coffee
  10. 9
      packages/rocketchat-channel-settings-mail-messages/server/lib/startup.js
  11. 65
      packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee
  12. 86
      packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.js

@ -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();
}
});
});

@ -8,7 +8,6 @@ Package.describe({
Package.onUse(function(api) {
api.use([
'ecmascript',
'coffeescript',
'templating',
'reactive-var',
'less',
@ -18,17 +17,17 @@ Package.onUse(function(api) {
]);
api.addFiles([
'client/lib/startup.coffee',
'client/lib/startup.js',
'client/stylesheets/mail-messages.less',
'client/views/channelSettingsMailMessages.html',
'client/views/channelSettingsMailMessages.coffee',
'client/views/channelSettingsMailMessages.js',
'client/views/mailMessagesInstructions.html',
'client/views/mailMessagesInstructions.coffee'
'client/views/mailMessagesInstructions.js'
], 'client');
api.addFiles([
'server/lib/startup.coffee',
'server/methods/mailMessages.coffee'
'server/lib/startup.js',
'server/methods/mailMessages.js'
], 'server');
});

@ -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…
Cancel
Save