I am trying to construct an email for some users. Code is running server-side. In the email I would like to have a link for the users to click on, but I am not having much luck.
I am trying to use Router.url() to set the href of an anchor. I can do console.log() and see the Router object is at least defined, but the link ends up being strange.
The code looks like this:
Meteor.methods({
sendSubmissionEmail: function(responseId) {
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
var formResponse = FormResponses.findOne({_id: responseId});
var toEmails = [];
_.each(Roles.getUsersInRole('ADMIN').fetch(), function(user) {
if (user.profile && user.profile.receivesResponseEmails) {
var email = _.findWhere(user.emails, {verified: true});
if (!email) {
console.log('No verified email address was found for ' + user.username + '. Using unverified email instead.');
email = _.first(user.emails);
}
if (email) {
toEmails.push(email.address);
}
}
});
if (toEmails && toEmails.length > 0) {
console.log('Sending an email to the following Admins: ' + toEmails);
console.log('Router: ', Router);
Email.send({
from: 'noreply#strataconsulting.us',
to: toEmails,
subject: 'Form Response for Form "' + formResponse.form_title + '" Ready For Approval',
html: '<p>Form Response for Form ' + formResponse.formTitle + ' is now ready for your approval.</p>'
});
}
}
});
And the resulting email:
====== BEGIN MAIL #0 ======
MIME-Version: 1.0
From: noreply#strataconsulting.us
To: testuser4#codechimp.net
Subject: Form Response for Form "undefined" Ready For Approval
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
<p>Form Response for Form Test Form One is now ready for your approval.</p>
====== END MAIL #0 ======
First, there is a strange "3D" appearing prior to the first " of the href, then the return or Router.url() is always undefined. Just to make sure the call was right, I simulated it in Chrome's dev tools console by doing the following:
var fr = FormResponses.findOne({_id: '1234567890'});
Router.url('editResponse', fr);
As expected this spits out the full URL path to my editResponse route with the correct ID set. Is Router.url() a client-only call? If so, how do I get the URL to a route server-side? All routes are defined for both client and server.
Here:
var fr = FormResponses.findOne({_id: '1234567890'});
Router.url('editResponse', fr);
You're passing the result of the Find as a parameter. It'll look like
{ _id: ..., otherStuff: ...}
But in your code you're not passing an object, you're just passing a string:
Router.url('editResponse', formResponse.id)
That explains the "undefined".
The 3D is very odd.
Related
I have a form in googlescript where I can add a user to a sheet.
Is there a way to implement some lines in that code so the script adds a post on a wordpress page?
I read that it's possible via wp_insert_post , but I have no idea how that works in my case.
EDIT:
As Spencer suggested I tried to do it via WP REST API.
The following code seems to be working .............
function httpPostTemplate() {
// URL for target web API
var url = 'http://example.de/wp-json/wp/v2/posts';
// For POST method, API parameters will be sent in the
// HTTP message payload.
// Start with an object containing name / value tuples.
var apiParams = {
// Relevant parameters would go here
'param1' : 'value1',
'param2' : 'value2' // etc.
};
// All 'application/json' content goes as a JSON string.
var payload = JSON.stringify(apiParams);
// Construct `fetch` params object
var params = {
'method': 'POST',
'contentType': 'application/json',
'payload': payload,
'muteHttpExceptions' : true
};
var response = UrlFetchApp.fetch(url, params)
// Check return code embedded in response.
var rc = response.getResponseCode();
var responseText = response.getContentText();
if (rc !== 200) {
// Log HTTP Error
Logger.log("Response (%s) %s",
rc,
responseText );
// Could throw an exception yourself, if appropriate
}
else {
// Successful POST, handle response normally
Logger.log( responseText );
}
}
But I get the error:
[16-09-28 21:24:29:475 CEST] Response (401.0)
{"code":"rest_cannot_create","message":"Sorry, you are not allowed to
create new posts.","data":{"status":401}}
Means: I have to authenticate first.
I installed the plugin: WP REST API - OAuth 1.0a Server
I setup a new user and got a client key and client user.
But from here I have no clue what to do : /
It is possible. Wordpress has a REST API. I can be found at:
http://v2.wp-api.org/
You will use the UrlFetchApp Service to access this api. Documentation can be found at:
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app
Read the docs and try to write some code. It you get stuck post the code that is confusing you here and I'll update this answer.
You should add you authentification in the header :
var headers = {
... ,
'Authorization' : 'Basic ' + Utilities.base64Encode('USERNAME:PASSWORD'),
};
And then add your header in your parameters :
var params = {
'method': 'POST',
'headers': headers,
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
}
And then use UrlfetchApp.fetch
var response = UrlFetchApp.fetch("https://.../wp-json/wp/v2/posts/", params)
Logger.log(response);
You need to pass the basic auth, like this:
// Construct `fetch` params object
var params = {
'method': 'POST',
'contentType': 'application/json',
'payload': payload,
'muteHttpExceptions' : true,
"headers" : {
"Authorization" : "Basic " + Utilities.base64Encode(username + ":" + password)+"",
"cache-control": "no-cache"
}
};
thank you for giving me these important links.
<3
I installed WP REST API and the OAuth plugin.
In the documentation is written:
Once you have WP API and the OAuth server plugins activated on your
server, you’ll need to create a “client”. This is an identifier for
the application, and includes a “key” and “secret”, both needed to
link to your site.
I couldn't find out how to setup a client?
In my GoogleScriptCode according to the WP API I get the error:
{"code":"rest_cannot_create","message":"Sorry, you are not allowed to create new posts.","data":{"status":401}}
Edit: I found it - it's under User/Application
I'll try to figure it out and get back to you later.
It looks like the email package in Meteor now allows adding attachments similar to how MailComposer does. On my server I have:
Meteor.startup( function() {
process.env.MAIL_URL = "smtp://<my maligun info here>";
});
Meteor.methods({
sendEmail: function (to, from, subject, text, attachment) {
// Let other method calls from the same client start running,
// without waiting for the email sending to complete.
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text,
attachment: attachment
});
}
});
Inside the app I'll have a helper like:
Template.donateEmail.events({
'click #send-donate-email': function() {
var attachment = {
fileName: "Demographics3.numbers",
filePath: "/Users/Opal/Desktop/Demographics3.numbers"
};
var emailCompose = document.getElementById('compose-donate-email').value;
var emailSubject = document.getElementById('subject-donate-email').value;
Meteor.call('sendEmail',
"some#email.com", //Session.get('keyDonateEmailSendList'),
'some2#email.com',
emailSubject,
emailCompose,
attachment)
}
});
I can get emails to send, but sending but there's no attachments. And the documentation is confusing. Anyone have any more info on this? I'm missing something somewhere.
Problem solved. Two mistakes in my code. In the Email.send method, it needs to read
"attachments: <some name>" not "attachment: <some name>".
The second issue is the making sure one specifies the correct absolute path, which in my case on a Mac would be:
"Volumes/Macintosh\ HD/Users/Opal/Desktop/<filename>"
I have found that Apple .numbers files aren't openable, but they will attach. Other files should be OK.
I'm trying to use google apps script to login to an ASP.Net website and scrape some data that I typically have to retrieve manually. I've used Chrome Developer tools to get the correct payload names (TEXT_Username, TEXT_Password, _VIEWSTATE, _VIEWSTATEGENERATOR), I also got a ASP Net session Id to send along with my Post request.
When I run my function(s) it returns a Response Code = 200 if followRedirects is set to false and returns Response Code = 302 if followRedirects is set to true. Unfortunately in neither case do the functions successfully authenticate the website. Instead the HTML returned is that of the Login Page.
I've tried different header variants and parameters, but I can't seem to successfully login.
Couple of other points. When I do the login in Chrome using the Developer tools, the response code appears to be 302 Found.
Does anyone have any suggestions on how I can successfully login to this site. Do you see any errors in my functions that could be the cause of my problems. I'm open to any and all suggestions.
My GAS functions follow:
function login(cookie, viewState,viewStateGenerator) {
var payload =
{
"__VIEWSTATE" : viewState,
"__VIEWSTATEGENERATOR" : viewStateGenerator,
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
};
var header = {'Cookie':cookie};
Logger.log(header);
var options =
{
"method" : "post",
"payload" : payload,
"followRedirects" : false,
"headers" : header
};
var browser = UrlFetchApp.fetch("http://tnetwork.trakus.com/tnet/Login.aspx?" , options);
Utilities.sleep(1000);
var html = browser.getContentText();
var response = browser.getResponseCode();
var cookie2 = browser.getAllHeaders()['Set-Cookie'];
Logger.log(response);
Logger.log(html);
}
function loginPage() {
var options =
{
"method" : "get",
"followRedirects" : false,
};
var browser = UrlFetchApp.fetch("http://tnetwork.trakus.com/tnet/Login.aspx?" , options);
var html = browser.getContentText();
// Utilities.sleep(500);
var response = browser.getResponseCode();
var cookie = browser.getAllHeaders()['Set-Cookie'];
login(cookie);
var regExpGen = new RegExp("<input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"(.*)\" \/>");
var viewStateGenerator = regExpGen.exec(html)[1];
var regExpView = new RegExp("<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"(.*)\" \/>");
var viewState = regExpView.exec(html)[1];
var response = login(cookie,viewState,viewStateGenerator);
return response
}
I call the script by running the loginPage() function. This function obtains the cookie (session id) and then calls the login function and passes along the session id (cookie).
Here is what I see in the Google Developer tools Network section when I login using Google's Chrome browser:
Remote Address: 66.92.89.141:80
Request URL: http://tnetwork.trakus.com/tnet/Login.aspx
Request Method: POST
Status Code:302 Found
**Request Headers** view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language: en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Content-Length: 252
Content-Type:application/x-www-form-urlencoded
Cookie: ASP.NET_SessionId=jayaejut5hopr43xkp0vhzu4; userCredentials=username=myUsername; .ASPXAUTH=A54B65A54A850901437E07D8C6856B7799CAF84C1880EEC530074509ADCF40456FE04EC9A4E47D1D359C1645006B29C8A0A7D2198AA1E225C636E7DC24C9DA46072DE003EFC24B9FF2941755F2F290DC1037BB2B289241A0E30AF5CB736E6E1A7AF52630D8B31318A36A4017893452B29216DCF2; __utma=260442568.1595796669.1421539534.1425211879.1425214489.16; __utmc=260442568; __utmz=260442568.1421539534.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=190106350.1735963725.1421539540.1425152706.1425212185.18; __utmc=190106350; __utmz=190106350.1421539540.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:tnetwork.trakus.com
Origin:http://tnetwork.trakus.com
Referer:http://tnetwork.trakus.com/tnet/Login.aspx?
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36
**Form Dataview** sourceview URL encoded
__VIEWSTATE: O7YCnq5e471jHLqfPre/YW+dxYxyhoQ/VetOBeA1hqMubTAAUfn+j9HDyVeEgfAdHMl+2DG/9Gw2vAGWYvU97gml5OXiR9E/9ReDaw9EaQg836nBvMMIjE4lVfU=
__VIEWSTATEGENERATOR:F4425990
TEXT_Username:myUsername
TEXT_Password:myPassword
BUTTON_Submit: Log In
Update: It appears that the website is using an HttpOnly cookie. As a result, I don't think I am capturing the whole cookie and therefore my header is not correct. As a result, I believe I need to set followRedirects to false and handle the redirect and cookie manually. I'm currently researching this process, but welcome input from anyone who has been down this road.
I was finally able to successfully login to the page. The issue seems to be that the urlFetchApp was unable to follow the redirect. I credit this stackoverflow post: how to fetch a wordpress admin page using google apps script
This post described the following process that led to my successful login:
Set followRedirect to false
Submit the post and capture the cookies
Use the captured cookie to issue a get with the appropriate url.
Here is the relevant code:
var url = "http://myUrl.com/";
var options = {
"method": "post",
"payload": {
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
"BUTTON_Submit" : "Log In",
},
"testcookie": 1,
"followRedirects": false
};
var response = UrlFetchApp.fetch(url, options);
if ( response.getResponseCode() == 200 ) {
// Incorrect user/pass combo
} else if ( response.getResponseCode() == 302 ) {
// Logged-in
var headers = response.getAllHeaders();
if ( typeof headers['Set-Cookie'] !== 'undefined' ) {
// Make sure that we are working with an array of cookies
var cookies = typeof headers['Set-Cookie'] == 'string' ? [ headers['Set-Cookie'] ] : headers['Set-Cookie'];
for (var i = 0; i < cookies.length; i++) {
// We only need the cookie's value - it might have path, expiry time, etc here
cookies[i] = cookies[i].split( ';' )[0];
};
url = "http://myUrl/Calendar.aspx";
options = {
"method": "get",
// Set the cookies so that we appear logged-in
"headers": {
"Cookie": cookies.join(';')
}
}
...
I notice that the provided Chrome payload includes BUTTON_Submit: Log In but your POST payload does not. I have found that for POSTs in GAS things go much more smoothly if I explicitly set a submit variable in my payload objects. In any case, if you're trying to emulate what Chrome is doing, this is a good first step.
So in your case, it's a one line change:
var payload =
{
"__VIEWSTATE" : viewState,
"__VIEWSTATEGENERATOR" : viewStateGenerator,
"TEXT_Username" : "myUserName",
"TEXT_Password" : "myPassword",
"BUTTON_Submit" : "Log In"
};
I use Meteor v1 to buid un app, and to be able to send a email from my app, I add Email package.
This is my code on the client
Template.Home.events({
'click button': function(event, template){
event.preventDefault();
var depart = template.find('[id=exampleInputEmail1]').value;
var arrive = template.find('[id=exampleInputPassword1]').value;
var email = template.find('[id=exampleInputPassword1m]').value;
var nom = template.find('[id=exampleInputPassword1s]').value;
var telephone = template.find('[id=exampleInputPassword1n]').value;
var element = template.find('[id=exampleInputPassword1j]').value;
Meteor.call('sendEmail', 'nwabdou85#yahoo.fr', email, 'Faites moi un devis rapide svp', 'This is a test of Email.send.');
}
});
And the server one is
Meteor.startup(function() {
var username = "postmaster%40sandboxxxxxxxx.mailgun.org";
var password = "xxxxxxxxxxx";
var server = "smtp.mailgun.org";
var port = "587"
process.env.MAIL_URL = 'smtp://' + encodeURIComponent(username) + ':' + encodeURIComponent(password) + '#' + encodeURIComponent(server) + ':' + port;
});
// In your server code: define a method that the client can call
Meteor.methods({
'sendEmail': function (to, from, subject, text) {
// check([to, from, subject, text], [String]);
this.unblock();
Email.send({
to: to,
from: from,
subject: subject,
text: text
});
}
});
but it does not work !! it throw out this error on consol : Error invoking Method 'sendEmail': Internal server error [500]
Can you even have this issue and hwo do you fixe it ??
I would suggest switching your hosting to Heroku, which is free but more configurable. Try reading my recent article on the subject, should give you some hints: http://joshowens.me/modulus-vs-heroku-vs-digital-ocean/.
If that is a 500 error from mailgun then its something on their side not yours. try accessing your dashboard on mailgun and see if you can get some info from there. I spent abit of time trying to get this right and it was all to do with getting the Mail url correct.
I remember in the bulletproof meteor you should use Meteor.defer function to delay your email sending process. Usually sending email caused response timeout.
Again, this.unblock might not useful in this case. Please try to comment out it if the first way doesn't work.
encodeURIcomponent would convert something from sam#sam.com to sam%40sam.com.
Your username is already URI encoded, so doesn't need to be further encoded. In this case, you are double encoding the username, and hence was probably failing with an authentication error.
I'm presented with an url with an "#" sign in it:
curl http://subdomain:token#localhost:9292/aaa/bbb
works perfectly
But I can't get it to work with node.js http.request, probably because I don't understand what the "#" is doing (and somehow can't find a clear answer on google).
Anyone care to explain?
Here's my current node.js code
var http_options = {
method : "GET"
, url : subdomain + ":" + token + "#" + Config.API.url
, path : "/aaa/bbb"
};
var req = http.request(http_options, function (response) {
// ...
});
req.on('error', function (error) {
console.log('error: ' + error);
});
which produces:
error: ECONNREFUSED
The # is dividing the user / password part from the location part.
the curl line you wrote send a HTTP Authenticate (BASIC authentication) with the request.
curl http://subdomain:token#localhost:9292/aaa/bbb
means: Get localhost:9292/aaa/bbb and do it as user: subdomain password token
I have no idea how to do that in node.js, but you'll figure it out, now that you know what it does.