How can I send email notifications with Parse and Mandrill? - javascript

I am trying to use Mandrill to send an event-based email notification to the users of my web app. I am using Parse with Back4App.
In this tutorial (https://docs.back4app.com/docs/integrations/parse-server-mandrill/), the hosting providers suggest using the following method to call the Mandrill cloud code from an Android application:
public class Mandrill extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Parse.initialize(new Parse.Configuration.Builder(this)
.applicationId("your back4app app id”)
.clientKey(“your back4app client key ")
.server("https://parseapi.back4app.com/").build()
);
Map < String, String > params = new HashMap < > ();
params.put("text", "Sample mail body");
params.put("subject", "Test Parse Push");
params.put("fromEmail", "someone#example.com");
params.put("fromName", "Source User");
params.put("toEmail", "other#example.com");
params.put("toName", "Target user");
params.put("replyTo", "reply-to#example.com");
ParseCloud.callFunctionInBackground("sendMail", params, new FunctionCallback < Object > () {
#Override
public void done(Object response, ParseException exc) {
Log.e("cloud code example", "response: " + response);
}
});
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mandrill);
}
}
How can I implement this in JavaScript with the Parse JavaScript SDK?
This is what I've done so far but it won't send an email. I have Mandrill set up, as well as a verified email domain and valid DKIM and SPF.
// Run email Cloud code
Parse.Cloud.run("sendMail", {
text: "Email Test",
subject: "Email Test",
fromEmail: "no-reply#test.ca",
fromName: "TEST",
toEmail: "test#gmail.com",
toName: "test",
replyTo: "no-reply#test.ca"
}).then(function(result) {
// make sure to set the email sent flag on the object
console.log("result :" + JSON.stringify(result));
}, function(error) {
// error
});
I don't even get a result in the console, so I figure the cloud code is not even executing.

You have to add the Mandrill Email Adapter to the initialisation of your Parse Server, as described on their Github page. Also check the Parse Server Guide for how to initialise or use their example project.
Then set up Cloud Code by following the guide. You'll want to either call a Cloud Code function using your Android app or from any Javascript app, or use beforeSave or afterSave hooks of a Parse Object directly in Cloud Code, which allow you to send Welcome Emails when a user signs up. That could come in handy if you want to implement behaviour based emails based on object updates. Plus, because it is on the server and not the client, it is easier to maintain and scale.
To make the Cloud Code function actually send an email via Mandrill, you need to add some more code to your Cloud Code function. First, add a file with these contents:
var _apiUrl = 'mandrillapp.com/api/1.0';
var _apiKey = process.env.MANDRILL_API_KEY || '';
exports.initialize = function(apiKey) {
_apiKey = apiKey;
};
exports.sendTemplate = function(request, response) {
request.key = _apiKey;
return Parse.Cloud.httpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
url: 'https://' + _apiUrl + '/messages/send-template.json',
body: request,
success: function(httpResponse) {
if (response) {
response.success(httpResponse);
}
return Parse.Promise.resolve(httpResponse);
},
error: function(httpResponse) {
if (response) {
response.error(httpResponse);
}
return Parse.Promise.reject(httpResponse);
}
});
};
Require that file in your Cloud Code file, and use it like any other Promise.
var Mandrill = require("./file");
Mandrill.sendTemplate({
template_name: "TEMPLATE_NAME",
template_content: [{}],
key: process.env.MANDRILL_API_KEY,
message: {
global_merge_vars: [{
name: "REPLACABLE_CONTENT_NAME",
content: "YOUR_CONTENT",
}],
subject: "SUBJECT",
from_email: "YOUR#EMAIL.COM",
from_name: "YOUR NAME",
to: [{
email: "RECIPIENT#EMAIL.COM",
name: "RECIPIENT NAME"
}],
important: true
},
async: false
})
.then(
function success() {
})
.catch(
function error(error) {
});
Make sure you create a template on Mailchimp, right click it and choose "Send to Mandrill", so that you can use that template's name when sending via the API.
It's a bit involved, but once set up, it works like a charm. Good luck!

Related

Automate Google Cloud Print from Drive Folder

To preface, I have Google Cloud Print working through apps script. I have OAuth2 setup, and I was able to setup a Cloud Print API that prints a single file in my Google Drive to a printer on my Cloud Print.
With that said, I'm looking for a way to automate my script so that when a document gets placed in a specific folder on my Google Drive, it will print automatically. I've searched around and was unable to find anything similar. Here's my starting point (which was found here from a very helpful tutorial):
function printGoogleDocument(docId, docTitle) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": myPrinterId,
"content": docId,
"title": docTitle,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
So when I fill in my docID and PrinterID, it works fine for a single document. But like I said, I'm trying to automate this based on new files in a Drive folder. Any suggestions?

How to use servicebus topic sessions in azure functionapp using javascript

I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.

How to prevent current user get notified?

I'm making an app that allows user to like and comment on other user post. I'm using Parse as my backend. I'm able to notified user everytime their post liked or commented. However if current user like or comment on their own post this current user still notified. How can I prevent this?
Here is the js code that I use:
Parse.Cloud.afterSave('Likes', function(request) {
// read pointer async
request.object.get("likedPost").fetch().then(function(like){
// 'post' is the commentedPost object here
var liker = like.get('createdBy');
// proceed with the rest of your code - unchanged
var query = new Parse.Query(Parse.Installation);
query.equalTo('jooveUser', liker);
Parse.Push.send({
where: query, // Set our Installation query.
data: {
alert: message = request.user.get('username') + ' liked your post',
badge: "Increment",
sound: "facebook_pop.mp3",
t : "l",
lid : request.object.id,
pid: request.object.get('likedPostId'),
lu : request.user.get('username'),
ca : request.object.createdAt,
pf : request.user.get('profilePicture')
}
}, {
success: function() {
console.log("push sent")
},
error: function(err) {
console.log("push not sent");
}
});
});
});
If I understand the context of where this code is correctly,
I recommend checking
if request.user.get("username") != Parse.CurrentUser.get("username")
Before sending out the push notification
Where is your cloud function being called from? If you're calling it from your ios code, then before you call the cloud code function, just prelude it with something like this:
if (PFUser.currentUser?.valueForKey("userName") as! String) != (parseUser.valueForKey("userName") as! String)

How to access gmail API?

I generate my JWT, if my token is correct why dont work ? in Google Developers Console i enabled gmail plus youtube and other API, in credentials generate and download json
{
"private_key_id": "22dcf",
"private_key": "-----BEGIN PRIVATE KEY-----(remove)-----END PRIVATE KEY-----\n",
"client_email": "vgfjjc6#developer.gserviceaccount.com",
"client_id": "jc6.apps.googleusercontent.com",
"type": "service_account"
}
first generate token
var sHead=JSON.stringify({"alg":"RS256","typ":"JWT"});
var iat=timeStampf();
var exp=iat+3600;
var sPayload=JSON.stringify({
"iss":client_email,
"scope":scope,//gmail scope https://mail.google.com/
"aud":"https://www.googleapis.com/oauth2/v3/token",
"exp":exp,
"iat":iat
});
var sJWS = KJUR.jws.JWS.sign("RS256", sHead,sPayload, private_key);
var paramstoken="grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-ty
pe%3Ajwt-bearer&assertion="+sJWS
getToken("POST","/oauth2/v3/token",paramstoken,jsonData,replier);
/*rest petition return 200 OK
{
"access_token" : "1bHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
"token_type" : "Bearer",
"expires_in" : 3600
}*/
next i test my token
function testToken(accessToken,replier)
{
// /gmail/v1/users/me/messages /plus/v1/people/me
var client = vertx.createHttpClient().host(urlbase).port(443).ssl(true).maxPoolSize(10);
var request = client.request("GET", "/gmail/v1/users/me/messages", function(resp) {
console.log('server returned status code: ' + resp.statusCode());
console.log('server returned status message: ' + resp.statusMessage());
resp.bodyHandler(function(body) {
replier(JSON.parse(body.toString()));
});
});
request.headers()
.set("Content-type", contentType)
.set("Authorization", "Bearer "+accessToken);
request.end();
client.close();
}
if i use google+ scope and this petition the answer is 200 ok
https://www.googleapis.com/auth/plus.me /plus/v1/people/me
{
"kind":"plus#person",
"etag":"\"LR9iFZQGXELLHS07eQ\"",
"objectType":"person","id":"1149981343","displayName":"","name":{"familyName":"","givenName":""},"image":{"url":"https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg?sz=50","isDefault":true},"isPlusUser":false,"language":"en_US","circledByCount":0,"verified":false}
but if i try with gmail
{"error":{"errors":[{"domain":"global","reason":"failedPrecondition","message":"Bad Request"}],"code":400,"message":"Bad Request"}}
In case of GMail, you are accessing a particular user's data, so when creating the JWT, you need to specify the user whom you are trying to impersonate, i.e. the user whose mailbox you want to access.
You can do this using the sub:"User's email address parameter" when forming the JWT Claim set
var sPayload=JSON.stringify({
"iss":client_email,
"sub":USER_EMAIL_ADDRESS
"scope":scope,//gmail scope https://mail.google.com/
"aud":"https://www.googleapis.com/oauth2/v3/token",
"exp":exp,
"iat":iat
});

Using Facebook request dialog with Meteor

I'm trying to send an "app" invite to user friends using the Facebook JavaScript SDK.
Here is a template event when click the Facebook button:
"click #fb": function (e, tmp) {
Meteor.loginWithFacebook({
requestPermissions: ['user_likes',
'friends_about_me',
'user_birthday',
'email',
'user_location',
'user_work_history',
'read_friendlists',
'friends_groups',
'user_groups']
}, function (err) {
if (err) {
console.log("error when login with facebook " + err);
} else {
FB.api('/' + Meteor.user().services.facebook.id + '/friends', { fields: 'name,picture' }, function (response) {
if (response && response.data) {
friends = response.data;
friends_dep.changed();
}
});
}
});
}
after that i want the user to invite people to my app, my code looks like this (another template event):
FB.ui({method: 'apprequests',
message: 'My Great Request'
}, function(response) {
if (response && response.post_id) {
alert('Post was published.');
} else {
alert('Post was not published.');
}
}
);
And it's working. There is a Facebook dialog with all the user friends, but when trying to send the message, I get the response error = 'Post was not published.'
What am I doing wrong here?
Basically the user can build a group - and I want the user to be able to invite his facebook friends into that group. Is there anyway that when sending the request the reciver will just press "yes" and will be automatically added to the sender group?
note I'm using my local machine aka localhost:3000
Can you try removing the && response.post_id portion from the if statement?
According to the Facebook API docs for the Requests Dialog: https://developers.facebook.com/docs/reference/dialogs/requests/ the response will just have 'request' and 'to' data. It looks like you've copy and pasted your callback from an example they give for the Posts Dialog. If you still get an error after removing this then you aren't getting a response, I am unsure how the JS SDK handles responses. If you can get other API calls to work using js sdk then I'm really not sure.
I recently worked with the Facebook API and opted not to use the JS SDK because it seemed to be at odds with using the accounts-facebook package. I'm curious if you're using that too.
Some Facebook API calls like creating a Post (and possibly this one) do require a dialog box, I'll outline how I got around this without using the JS SDK in case it helps you or anyone else. I would just form the URL client side and open a popup window e.g. here's how I handled sending a post:
'click .send-message': function() {
var recipient = this.facebook_id;
var config = Accounts.loginServiceConfiguration.findOne({service: 'facebook'});
var url = "http://www.facebook.com/dialog/feed?app_id=" + config.appId +
"&display=popup&to=" + recipient + "&redirect_uri=" + Meteor.absoluteUrl('_fb?close');
window.open(url, "Create Post", "height=240,width=450,left=100,top=100");
}
Then to get the response server side:
WebApp.connectHandlers
.use(connect.query())
.use(function(req, res, next) {
if(typeof(Fiber)=="undefined") Fiber = Npm.require('fibers');
Fiber(function() {
try {
var barePath = req.url.substring(0, req.url.indexOf('?'));
var splitPath = barePath.split('/');
if (splitPath[1] !== '_fb') {
return next();
}
if (req.query.post_id) {
//process it here
}
res.writeHead(200, {'Content-Type': 'text/html'});
var content = '<html><head><script>window.close()</script></head></html>';
res.end(content, 'utf-8');
} catch (err) {
}
}).run();
});
This code is very similar to the code used in the oauth packages when opening the login popup and listening out for responses.

Categories

Resources