Mandrill with parse server not working on heroku migration - heroku

I have migrate app from parse.com to heroku with mLab and everything works fine except cloud code.
I am using Mandrill for sending email from parse cloud code which is not working with heroku
Here is what I have done so far:
Installed mandrill ~0.1.0 into parse-server-example and push the code to heroku app
Put the cloud code into '/cloud/main.js'
Called the function from iOS app which respond error as:
[Error]: Invalid function. (Code: 141, Version: 1.13.0).
Here is my code script:
Parse.Cloud.define("sendMail", function(request, response) {
var Mandrill = require('mandrill');
Mandrill.initialize('xxxxxx-xxxxx');
Mandrill.sendEmail({
message: {
text: "ffff",
subject: "hello",
from_email: "xxxxx#gmail.com",
from_name: "pqr",
to: [
{
email: "xxxxxxxxxx#gmail.com",
name: "trump"
}
]
},
async: true
},{
success: function(httpResponse) {
console.log(httpResponse);
response.success("Email sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
});
But after calling 'sendMail' function I am getting this error:
[Error]: Invalid function. (Code: 141, Version: 1.13.0).
================================== MailGun ==========================
Parse.Cloud.define('hello', function(req, res) {
var api_key = 'key-xxxxxxxxxxxxxx';
var domain = 'smtp.mailgun.org';
var mailgun = require('mailgun-js')({apiKey: api_key, domain: domain});
var data = {
from: 'xxxxxxxald#gmail.com',
to: 'xxxxx8#gmail.com',
subject: 'Hello',
text: 'Testing some Mailgun awesomness!'
};
mailgun.messages().send(data, function (error, body) {
console.log(body);
});
//res.success(req.params.name);
});

I had a similar problem with sendgrid, but I finally find a way around the problem.
I think this steps may help you,
Miss some brackets or some code separator? ( try rewritting the entire code in the main.js )
The app is actually running? ( when you type "heroku open" in the terminal you get the default message? ) - if not check step 1.
If the previous are not working, rollback to a safe build and Add the add-ons in the heroku dashboard instead of installing them yourself, then download the git and do any changes to git and then push.

Below I have pasted from cloud code main.js code that is working using Mandrill on heroku parse application to send password recovery e-mail.
in cloud code main.js:
var mandrill_key = process.env.MANDRILL_KEY;
var Mandrill = require('mandrill-api/mandrill');
var mandrill_client = new Mandrill.Mandrill(mandrill_key);
{
success: function(gameScore) {
//alert('New object created with objectId: ' + gameScore.id);
mandrill_client.messages.send(
{
message: {
html: "<p>Hello " + firstUser.get('fullname') + ",</p><p>We received your request to reset your password.</p><p>Your user name is <strong>" + firstUser.get('username') + "</strong>. Please click here to create a new password. This link will expire in one hour after this mail was sent</p><p>If you need additional help, just let us know.</p><p>SampleCompany Support<br>customerservice#example.com</p><p>Copyright Sample Company, Inc. 2014-2017</p>",
subject: "Sample Company Name account recovery",
from_email: "customerservice#example.com",
from_name: "Sample Company Name",
to: [
{
email: firstUser.get('email'),
name: firstUser.get('fullname')
}
]
},
async: true
},
//Success
function(httpResponse) {
console.log(httpResponse);
//alert("Email sent!");
},
//Failure
function(httpResponse) {
console.error(httpResponse);
//alert("Uh oh, something went wrong");
});
},
error: function(gameScore, error) {
console.error(error.message);
//alert('Failed to create new object, with error code: ' + error.message);
},
useMasterKey: true
})

Related

Parse Push's not delivered cloud code only

I'm running parse-server on ubuntu and can't seem to get push notifications working when sent in cloud code.
Push's work when using a REST api call (passing master key) but don't work when cloud code calls them.
What's interesting is that the cloud code Parse.Push() method returns a success and thus no error message.
My hypothesis is that this is a configuration problem, and the Parse.Push() method is referencing somethign I have incorrectly configured on the server.
here is my cloud function. This call works when sent via REST. and the success callback in cloud is always called.
Parse.Push.send(
{
// where: pushQueryClient,
channels: ["user_tkP7gurGzc"],
data:
{
alert: pushTextClient
}
},
{
success:function(){
console.log("push sent");
},
error: function(error){
console.log("push failed");
console.dir(error);
},
useMasterKey: true});
i think you have an issue with the useMasterKey parameter.
Please try to use this code in order to send the push notification:
Parse.Push.send({
where: whereQuery,
data: {
alert: {
title: request.params.title,
body: request.params.body
},
type: request.params.type,
sound: 'default'
}
}, {
useMasterKey: true
}).then(function() {
response.success();
}, function(error) {
response.error("Push failed " + error);
});
In this code i use Promises which is the best practice and also wrap useMasterKey in a separate object

How can i create a subscription plan on a connected account in Stripe?

I am trying to create a subscription plan on a stripe connect managed account. I tried the following code:
Parse.Cloud.define("createSubscription", function (request, response) {
Parse.Cloud.httpRequest({
method:"POST",
url: "https://" + "sk_test_****************" + ':#' + "api.stripe.com/v1" + "/accounts/" + 'acct_**********' + "/plans/",
headers: {
'Authorization': 'Basic ********************'
},
body: {
'amount': 2000,
'interval': 'month',
'name': 'JPGB Plan',
'currency': 'usd',
'id':'first Plan',
},
success: function(httpResponse) {
response.success(httpResponse.text);
},
error: function(httpResponse) {
response.error('Request failed with response code' + httpResponse.status);
}
});
});
But this failed with a 404 (the requested resource doesn't exist) error.
This is how I did it.
Parse.Cloud.define("createAccountPlan", function (request, response) {
Parse.Cloud.httpRequest({
method:"POST",
url: "https://" + "sk_test_****************" + ':#' + "api.stripe.com/v1/plans",
headers: {
'Stripe-Account': request.params.accountId
},
body: {
'amount': request.params.amount,
'interval': 'day',
'interval_count':request.params.intervalCount,
'name': request.params.planName,
'currency': 'usd',
'id':request.params.planId,
},
success: function(httpResponse) {
response.success(httpResponse.text);
},
error: function(httpResponse) {
response.error('Request failed with response code' + httpResponse.status);
}
});
});
What i think you should do is not to execute a direct http request to stripe REST API but to use strip node-js SDK that will do it and more for you.
In order to achieve it in parse server you need to do the following steps:
inside your parse-server project enter the following command
npm install stripe
this will install stripe into your parse-server project
In your cloud code require the stripe node SDK
var stripe = require('stripe')(' your stripe API key ');
Call to the create subscription function which available under the stripe object that you required
stripe.subscriptions.create({
customer: "{YOUR_CUSTOMER_ID}",
plan: "{PLAN_IDENTIFIER}"
}, function(err, subscription) {
// asynchronously called
}
);
Then if you need additional service call to stripe you can do it in the same way.
All the services that you can run with stripe can be found in here
It's always better to use SDK's when you can because SDK's make your
life much more easy, are handling all the things for you behind the
scenes and usually are maintained by the company who provided them (in
this case its stripe)
From the Stripe connect docs:
Authentication via the Stripe-Account header
The first, preferred, authentication option is to use your—the platform account’s—secret key and pass a Stripe-Account header identifying the connected account for which the request is being made.
(demo showing making a customer)
All of Stripe’s libraries support this style of authentication on a per-request basis
Stripe docs are a little subtle here, but this means you can use the same technique to make a subscription for a customer on a connected account. You can also use it to make the products and plans for that connected account too. and anything else you want to do on behalf of the connected customer:
(async function(){
let subscription = await stripe.subscriptions.create({
customer: "someCustomerID",
plan: "planID"
},{
stripe_account: "connectedStripeAccountID"
});
})();

Saving or Creating a Parse File in Parse Cloud code

I am trying to create a Parse cloud code function that would run a query and then put the results of the query in csv file and finally using the mailgun plugin send it out to a receipient.
Unfortunately I cannot figure out how to create a Parse File in cloud code. Suggestions?
Parse.cloud.define("exportDataViaEmail", function(request, response){
var query = new Parse.Query("Diaper");
var today = new Date();
var startTime = new Date(today - 1000 * 60 * 60 * 24 * (7*52+1));
query.lessThan("logCreationDate", today);
query.greaterThan("logCreationDate", startTime);
query.find({
success: {
//TODO I want store this in a Parse File but how?
},
error :{
}
});
})
/*
* Send email via mailgun
*/
Parse.Cloud.define("sendEmail", function(request, response){
Mailgun.sendEmail({
to: "myemail#gmail.com",
from: "hello#example.com",
subject: "Hello From example App",
text: "Using Parse and Mailgun is great!"
}, {
success: function(httpResponse) {
console.log(httpResponse);
response.success("Email sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
})
Using files in cloud code is easy and is thoroughly documented in the Parse Javascript Guide
It's as simple as var file = new Parse.File("myfile.txt", bytes);

How can I read a local file in Cloud Code as a string?

I'm using Parse Cloud Code.
My system has a welcome message. I use MailGun to send it.
The problem I have is that the message now is an HTML file, so I would like to let the HTML file in my server, read it using Cloud Code and pass that info to MailGun.
Can I read a local text file using Cloud Code and have it in my program as a string?
Should I save that file in my public folder or in the same folder than my cloudcode program?
I'm not confident with MailGun, but I believe it should work like MailChimp or Mandrill. If so, you should be able to store on MailGun your whole HTML template and just have some template_vars to complete.
This is a sample code of our own way to send mail with HTML thanks to the Mandrill system
Parse.Cloud.define("sendMailTemplate", function(request, response) {
var emails = request.params.emails;
var template_name = request.params.template_name;
var template_merge_content = request.params.template_merge_content;
var subject = request.params.subject;
var Mandrill = require('cloud/mandrillTemplateSend.js');
if (subject === undefined) {
subject = 'Mail sent by Mandrill';
body = subject;
}
Parse.Config.get().then(function(config) {
Mandrill.initialize(config.get('Mandrill_key'));
}).then(function() {
_.each(emails, function(email) {
Mandrill.sendTemplate({
template_name: template_name,
template_content: [{
name: template_merge_content.username,
content: ''
}],
message: {
text: '',
subject: subject,
from_email: 'contact#yourdomain.com',
to: [{
email: email,
name: template_merge_content.username
}],
merge_vars: [{
rcpt: email,
vars: template_merge_content
}],
},
async: false
});
});
}).then(function() {
response.success('Success');
}, function(error) {
response.error(error);
});
});
This object template_merge_content is quiet important. It's an object where is saved all the dynamic vars which are send to complete your HTML mail.
According to http://blog.mailgun.com/transactional-html-email-templates/ it seems you have same kind of method to send your mail.
So final advice would be to NOT store your HTML template within any Parse's class, or to save it within https://parse.com/docs/js/api/symbols/Parse.Config.html

parse.com cloud code can't send email via mandrillapp

I'm trying to send an email via parse.com via mandrill. The examples are very easy to follow, but I'm getting a strange error.
here is my code:
Parse.Cloud.afterSave("ip", function(request) {
var IPLogger_config = require('cloud/mandrillapp_config.js');
var Mandrill = require('mandrill');
Mandrill.initialize(IPLogger_config.mandrillAppKey);
console.log('within afterSave for ip');
console.log(request.object.id);
var ip = Parse.Object.extend("ip");
var query = new Parse.Query(ip);
query.descending("createdAt");
query.limit(2); // limit to at most 2 results
query.find({
success: function(results){
console.log('success query');
console.log('got ' + results.length + ' results');
var newestIp = results[0];
var olderIp = results[1];
if (newestIp.get('ip') == olderIp.get('ip') ) {
// the newest ip and the older one are equal, do nothing.
console.log('No ip change');
} else
{
console.log('ip change!');
console.log(Mandrill.initialize);
console.log(Mandrill.sendEmail);
Mandrill.sendEmail({
message: {
text: "The IP of your server has changed! The new ip is: " + newestIp.get('ip') ,
subject: "The IP of your server has changed!",
from_email: "parse#cloudcode.com",
from_name: "IPLogger",
to: [
{
email: IPLogger_config.your_email,
name: IPLogger_config.your_name
}
]
},
async: true
},{
success: function(httpResponse) {
console.log(httpResponse);
response.success("Email sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
}
},
error: function (error){
console.log('no success for query');
console.error("Got an error " + error.code + " : " + error.message);
}
});
});
my mandrillapp_config.js looks like this:
var IPLogger_config = {};
IPLogger_config.mandrillAppKey = "xxx";
IPLogger_config.your_email = 'myemail#bla.com';
IPLogger_config.your_name = 'myName';
The mandrillAppKey is correctly set. I double checked that. Sending email from mandrill website also works. I just created a new account and did no other settings on the mandrill site.
I'm getting this error: "code":-1,"name":"ValidationError","message":"You must specify a key value". In https://www.parse.com/questions/sometimes-getting-mandrill-you-must-specify-a-key-value-error-when-sending-email is written that the header might be wrong, but as you can see on my log, the "Content-Type":"application/json; charset=utf-8" is set correctly.
I2014-06-09T22:34:20.601Z] {
"uuid":"fbb215c4-1d2a-e2da-23fc-a838bd6bf217",
"status":500,
"headers":{
"Access-Control-Allow-Credentials":"false",
"Access-Control-Allow-Headers":"Content-Type",
"Access-Control-Allow-Methods":"POST, GET, OPTIONS",
"Access-Control-Allow-Origin":"*",
"Connection":"close",
"Content-Encoding":"gzip",
"Content-Type":"application/json; charset=utf-8",
"Date":"Mon, 09 Jun 2014 22:34:20 GMT",
"Server":"nginx/1.6.0",
"Vary":"Accept-Encoding",
"X-Powered-By":"PHP/5.3.10-1ubuntu3.11"
},
"text":"{\"status\":\"error\",\"code\":-1,\"name\":\"ValidationError\",\"message\":\"You must specify a key value\"}",
"data":{"status":"error","code":-1,"name":"ValidationError","message":"You must specify a key value"},
"buffer":{"0":123,"1":34,"2":115,"3":116,"4":97,"5":116,"6":117,"7":115,"8":34,"9":58,"10":34,"11":101,"12":114,"13":114,"14":111,"15":114,"16":34,"17":44,"18":34,"19":99,"20":111,"21":100,"22":101,"23":34,"24":58,"25":45,"26":49,"27":44,"28":34,"29":110,"30":97,"31":109,"32":101,"33":34,"34":58,"35":34,"36":86,"37":97,"38":108,"39":105,"40":100,"41":97,"42":116,"43":105,"44":111,"45":110,"46":69,"47":114,"48":114,"49":111,"50":114,"51":34,"52":44,"53":34,"54":109,"55":101,"56":115,"57":115,"58":97,"59":103,"60":101,"61":34,"62":58,"63":34,"64":89,"65":111,"66":117,"67":32,"68":109,"69":117,"70":115,"71":116,"72":32,"73":115,"74":112,"75":101,"76":99,"77":105,"78":102,"79":121,"80":32,"81":97,"82":32,"83":107,"84":101,"85":121,"86":32,"87":118,"88":97,"89":108,"90":117,"91":101,"92":34,"93":125,"length":94,
"parent":{"0":123,"1":34,"2":115,"3":116,"4":97,"5":116,"6":117,"7":115,"8":34,"9":58,"10":34,"11":101,"12":114,"13":114,"14":111,"15":114,"16":34,"17":44,"18":34,"19":99,"20":111,"21":100,"22":101,"23":34,"24":58,"25":45,"26":49,"27":44,"28":34,"29":110,"30":97,"31":109,"32":101,"33":34,"34":58,"35":34,"36":86,"37":97,"38":108,"39":105,"40":100,"41":97,"42":116,"43":105,"44":111,"45":110,"46":69,"47":114,"48":114,"49":111,"50":114,"51":34,"52":44,"53":34,"54":109,"55":101,"56":115,"57":115,"58":97,"59":103,"60":101,"61":34,"62":58,"63":34,"64":89,"65":111,"66":117,"67":32,"68":109,"69":117,"70":115,"71":116,"72":32,"73":115,"74":112,"75":101,"76":99,"77":105,"78":102,"79":121,"80":32,"81":97,"82":32,"83":107,"84":101,"85":121,"86":32,"87":118,"88":97,"89":108,"90":117,"91":101,"92":34,"93":125,"length":94},"offset":0},"cookies":{}}
Where can be the problem? any ideas how to get it running?
thank you very much!
I finally found the problem. There was en error in the config script.
it need to look like this:
var IPLogger_config = {};
IPLogger_config.mandrillAppKey = "xxx";
IPLogger_config.your_email = 'myemail#bla.com';
IPLogger_config.your_name = 'myName';
exports.IPLogger_config = IPLogger_config;
in the main.jsfile, the resources of the config file need to be called like this:
var config = require('cloud/mandrillapp_config.js');
Mandrill.initialize(config.IPLogger_config.mandrillAppKey);
and now it works fine.

Resources