I am trying to creating a app which can send posts to tumblr using tumblr.js api.
I could send single image using the createPhotoPost method, but I have to send multiple image in a single post via this method.
From the documentation it says that createPhotoPost method has a "data" parameter which can be an array with "URL-encoded binary contents"
When ever I try to send something in the data Array it returns "[Error: form-data: Arrays are not supported.]".
Can someone please help to solve this issue and please explain what should we pass in the array (Really I am not getting what is URL-encoded binary contents)?
Thanks in advance
There is an error in tumblr.js
https://tumblr.github.io/tumblr.js/tumblr.js.html#line504
The documentation at https://www.tumblr.com/docs/en/api/v2#posting is correct.
Basically the issue is that its not supposed to be
data = [ one , two ] its litterally params['data[0]'] = one ; params['data[1]'] = two; (?A PHP Convention)
var request = require('request')// already a tumblr.js dependency
var currentRequest = request({
url:'https://api.tumblr.com/v2/blog/someblog.tumblr.com/post',
oauth:keys,
},function(err,response,body){
currentRequest//
debugger
cb()
})
var params = {
'type' :'photo',
'caption':'Click To Verify You Are A Robot',
}
var params_images = [
fs.createReadStream('image'),
fs.createReadStream('image')
]
// Sign it with the non-data parameters
currentRequest.form(params)
currentRequest.oauth(keys);
// Clear the side effects from form(param)
delete currentRequest.headers['content-type'];
delete currentRequest.body;
// And then add the full body
var form = currentRequest.form();
//###add params_images to params keys 'data[0]' 'data[1]' 'data[2]' ....
params_images.forEach(function(image,index){
params['data['+index+']']
})
for (var key in params) {
form.append(key, params[key]);
}
// Add the form header back
var form_headers = form.getHeaders()
for(var key in form_headers){
currentRequest[key] = form_headers[key]
}
Related
Our company has multiple brands and each brand has its own host name, but they are all part of the same site. We can let customers share baskets and other session information when they switch between brands via a redirect link using URLUtils.sessionRedirect.
But URLUtils is not available in content assets. Is it possible to form a session redirect link in content asset keeping all the session information?
Thanks in advance.
You can include dynamic content in Content Assets with the $include('Controller-Name', 'name1', 'value1', 'name2', 'value2', ...)$ syntax. See the MarkupText Class Documentation for more info on that syntax. The 'name1' and 'value1' parameters are mapped as query string attributes eg: Controller-Name?name1=value1&name2=value2
Create a controller that outputs the session redirect link you need, and call it via that syntax like: $include(Util-RenderSessionLink, 'siteID', 'foo')$
The controller would need to use a response Content-Type header of text/plain or something like that so that nothing is injected into the response. (eg: Storefront toolkit or tracking tags) For example:
response.setContentType('text/plain');
Alternatively, you could process the content asset for some sorts of keys that you perform find & replace operations on. For example, the following code does a find & replace on a Content Asset's body content for the key: '%%SessionLink%%'.
var ContentMgr = require('dw/content/ContentMgr');
var URLUtils = require('dw/web/URLUtils');
if (!empty(content) {
var content = ContentMgr.getContent('my-content-id');
var contentOut = "";
var viewData = {};
contentOut = content.custom.body.getMarkup()
.replace('%%SessionLink%%', URLUtils.sessionRedirect(...));
viewData.content = contentOut;
// then output your `pdict.content` key within a template with the appropriate encoding
}
If anybody else is running into this, we added a bit of client-side javascript that pickups up all outbound links and if it's one of our domains it sends them through a session redirect. This way we don't need content managers to fix very link between domains:
var domains = ["domaina.com", "domainb.com", "domainc.com"]
var sessionRedirectBase = '/s/Our-Site/dw/shared_session_redirect';
$(document).on("click.crossSite", "a", (e) => {
const href = $(e.currentTarget).attr("href");
if (href) { //does the link have a href
if (href.match(/^(http(s)?:)?\/\//)) { //is href an absolute url
const url = new URL(href);
if (url.hostname != window.location.hostname && domains.indexOf(url.hostname) > -1) { //is hostname not the current one and part of the domains array
e.preventDefault();
const sessionRedirect = `${sessionRedirectBase}?url=${encodeURIComponent(href)}`
window.location = sessionRedirect;
}
}
}
});
I'm quite the noob using Ionic or Angular for that matter. So as a cheat sheet I'm using the ionic-super-starter template (link below).
I am trying to make a get request to my API and it works just find if I'm doing it like this:
this.api.get('user/'+this.user.userId+'/entries?include=stuff&access_token=TOKEN');
but when I put the url params into an object it stops working:
let options = {
'include':'stuff',
'access_token':'TOKEN'
}
this.api.get('user/'+this.user.userId+'/entries', options);
The only error I get is "Unauthorized Request" since the options object including the access token was not appended to the url.
In the ionic-super-starter template the providers/api/api.ts calls .set() for each key in my params object:
if (params) {
reqOpts.params = new HttpParams();
for (let k in params) {
reqOpts.params.set(k, params[k]);
}
}
but according to Angular University this is not possible since "HTTPParams is immutable".
If it really was wrong to do this, I don't believe it would be in the ionic template. Nor would I believe that I would be the first person to come across this issue.
However, I am stuck here so any help would be appreciated.
Link to Angular University:
https://blog.angular-university.io/angular-http/#httprequestparameters
Link to ionic-super-starter:
https://github.com/ionic-team/starters/tree/master/ionic-angular/official/super
I think I figured it out myself:
if I write (in my src/providers/api/api.ts)
reqOpts.params = reqOpts.params.append(k, params[k]);
instead of
reqOpts.params.set(k, params[k]);
it works.
if you are using a loopback API as I am you might have nested objects like:
let options = {
"filter": {
"order": "date DESC"
},
"access_token":this.user._accessToken
};
this won’t work. try instead:
let options = {
"filter": '{"order":"date DESC"}',
"access_token":this.user._accessToken
};
The above screenshot is the sample of the Bounced Back Mail received.
I'm using the following code to extract the Body of the mail.
function test()
{
var BouncedEmails = GmailApp.search("label:test The following message was undeliverable ");
for( var i=0;i<BouncedEmails.length;i++)
{
var Gmessage = GmailApp.getMessagesForThread(BouncedEmails[i]);
for(var j=0;j<Gmessage.length;j++)
{
var body = Gmessage[j].getPlainBody();
Logger.log(body);
}
}
}
But when I am doing this, I got the following output.
As you can see the last part of the Body is missing, that is :
I also tried using :
var body = Gmessage[j].getBody();
instead of "GetPlainBody()" but the output was still the same.
On using :
var body = Gmessage[j].getRawContent();
I got this as output for the missing part, which seems to me as some sort of encoding.
So my question is, how do i extract the full content of the Bounced Back Mail?
Thank You.
I finally found the answer to my own question.
This has worked for me and will pretty much work for anyone on our planet.
function test()
{
var BouncedEmails = GmailApp.search("label:test The following message was undeliverable ");
for( var i=0;i<BouncedEmails.length;i++)
{
var threadId = BouncedEmails[i].getId();
var id = Session.getEffectiveUser().getEmail();
var body = Gmail.Users.Threads.get(id, threadId, {format : 'full'});
var messages = body.messages;
var payLoad = messages[0].payload.parts[2];
var string = JSON.stringify(payLoad);
Logger.log(string);
}
}
The solutions provided by #AmitAgarwal and #ShyamKansagra would also work for some cases, but which solution to use depends on what is your exact requirement.
Don't use Logger.log as it truncates the output after a certain number of lines. Log the output in a spreadsheet and you'll see that the full body is extracted with getPlainBody() or getBody().
I recently published a Google Script to get all bounced emails in Gmail and logs them to a Google sheet. It is open so can build upon that script.
I also tried using getBody(), getPlainBody() and getRawContent() methods on bounced back emails. I noticed that these methods didn't give entire body of the email i.e. the part with technical details was skipped entirely in the logs.
So, I used this following code(all credits to #Amit Agarwal), which I found in the link which Amit has shared in his answer and it gave me entire body of bounced back email.
Here is the code:
var t = "in:anywhere from:(mailer-daemon#google.com OR mailer-daemon#googlemail.com)";
GmailApp.search(t,0,500).forEach(function(t)
{
t.getMessages().forEach(function(r)
{
if(r.getFrom().indexOf("mailer-daemon")!==-1)
{
var i=r.getPlainBody();
Logger.log(i);
}
}
)
}
)
It worked for me and gave the entire content in the logs itself. Hope this helps.
I've setup a form using googledocs. I just want to have the actual data entered into the form emailed to me, as opposed to the generic response advising that the form has been completed.
I have no skill or experience with code etc, but was sure i could get this sorted. I've spent hours+hours and haven't had any luck.
My form is really basic.it has 5 fields. 4 of which are just text responses, and one multiple choice.
I found this tute online (http://www.labnol.org/internet/google-docs-email-form/20884/) which i think sums up what i'm trying to do, but have not been able to get it to work.
from this site i entered the following code:
function sendFormByEmail(e)
{
var email = "reports.mckeir#gmail.com";
var subject = "Google Docs Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
To this, i get the following response: ->
Your script, Contact Us Form Mailer, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.
The script is used by the document 100% Club.
Details:
Start Function Error Message Trigger End
12/3/12 11:06 PM sendFormByEmail TypeError: Cannot call method "toString" of undefined. (line 12) formSubmit 12/3/12 11:06 PM
Is anyone able to help shed some light on this for me? I'm guessing i'm not including some data neeeded, but i honestly have no clue.
Workaround http://www.labnol.org/internet/google-docs-email-form/20884/
You have to setup app script to forward the data as email.
I'll point to the comment above that solved it for me: https://stackoverflow.com/a/14576983/134335
I took that post a step further:
I removed the normal notification. The app script makes that generic text redundant and useless now
I modified the script to actually parse the results and build the response accordingly.
function sendFormByEmail(e)
{
var toEmail = "changeme";
var name = "";
var email = "";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Google Docs Form Submitted";
var message = "";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers) {
if (headers[i] = "Name") {
name = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Email") {
email = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Subject") {
subject = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Message") {
message = e.namedValues[headers[i]].toString();
}
}
// See https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
var mailOptions = {
name: name,
replyTo: email,
};
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(toEmail, subject, message, mailOptions);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
The script utilized in the example is extremely generic but very resilient to change because the message is built as a key/value pair of the form fields submitted.
If you use my script you'll have to tweak the for loop if statements to match your fields verbatim. You'll also want to edit the toEmail variable.
Thanks again for the question and answers. I was about to ditch Google Forms as the generic response was never enough for what I was trying to do.
Lastly, in response to the actual problem above "toString of undefined" specifically means one of the form fields was submitted as blank. If I had to guess, I would say the author only used this for forms where all the fields were required or a quick undefined check would've been put in place.
Something like the following would work:
for(var i in headers) {
var formValue = e.namedValues[headers[i]];
var formValueText = "";
if (typeof(formValue) != "undefined") {
formValueText = formValue.toString();
}
message += headers[i] + ' = '+ formvalueText + "\n\n";
}
I haven't tested this precisely but it's a pretty standard way of making sure the object is defined before trying methods like toString() that clearly won't work.
This would also explain Jon Fila's answer. The script blindly assumes all of the header rows in the response are sent by the form. If any of the fields aren't required or the spreadsheet has fields that are no longer in the form, you'll get a lot of undefined objects.
The script could've been coded better but I won't fault the author as it was clearly meant to be a proof of concept only. The fact that they mention the replyTo correction but don't give any examples on implementing it made it perfectly clear.
If this is a Google Form, do you have any extra columns in your spreadsheet that are not on the form? If you delete those extra columns then it started working for me.
You don't need to use a script. Simply go to Tools >> Notification Rules on your Google Spreadsheet. There you can change the settings to receive an email with your desired information every time the document is changed.
I am building a REST API for my project. The API for getting a given user's INFO is:
api.com/users/[USER-ID]
I would like to also allow the client to pass in a list of user IDs. How can I construct the API so that it is RESTful and takes in a list of user ID's?
If you are passing all your parameters on the URL, then probably comma separated values would be the best choice. Then you would have an URL template like the following:
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?id=id1,id2,id3,id4,id5
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
IMO, above calls does not looks RESTful, however these are quick and efficient workaround (y). But length of the URL is limited by webserver, eg tomcat.
RESTful attempt:
POST http://example.com/api/batchtask
[
{
method : "GET",
headers : [..],
url : "/users/id1"
},
{
method : "GET",
headers : [..],
url : "/users/id2"
}
]
Server will reply URI of newly created batchtask resource.
201 Created
Location: "http://example.com/api/batchtask/1254"
Now client can fetch batch response or task progress by polling
GET http://example.com/api/batchtask/1254
This is how others attempted to solve this issue:
Google Drive
Facebook
Microsoft
Subbu Allamaraju
I find another way of doing the same thing by using #PathParam. Here is the code sample.
#GET
#Path("data/xml/{Ids}")
#Produces("application/xml")
public Object getData(#PathParam("zrssIds") String Ids)
{
System.out.println("zrssIds = " + Ids);
//Here you need to use String tokenizer to make the array from the string.
}
Call the service by using following url.
http://localhost:8080/MyServices/resources/cm/data/xml/12,13,56,76
where
http://localhost:8080/[War File Name]/[Servlet Mapping]/[Class Path]/data/xml/12,13,56,76
As much as I prefer this approach:-
api.com/users?id=id1,id2,id3,id4,id5
The correct way is
api.com/users?ids[]=id1&ids[]=id2&ids[]=id3&ids[]=id4&ids[]=id5
or
api.com/users?ids=id1&ids=id2&ids=id3&ids=id4&ids=id5
This is how rack does it. This is how php does it. This is how node does it as well...
There seems to be a few ways to achieve this. I'd like to offer how I solve it:
GET /users/<id>[,id,...]
It does have limitation on the amount of ids that can be specified because of URI-length limits - which I find a good thing as to avoid abuse of the endpoint.
I prefer to use path parameters for IDs and keep querystring params dedicated to filters. It maintains RESTful-ness by ensuring the document responding at the URI can still be considered a resource and could still be cached (although there are some hoops to jump to cache it effectively).
I'm interested in comments in my hunt for the ideal solution to this form :)
You can build a Rest API or a restful project using ASP.NET MVC and return data as a JSON.
An example controller function would be:
public JsonpResult GetUsers(string userIds)
{
var values = JsonConvert.DeserializeObject<List<int>>(userIds);
var users = _userRepository.GetAllUsersByIds(userIds);
var collection = users.Select(user => new { id = user.Id, fullname = user.FirstName +" "+ user.LastName });
var result = new { users = collection };
return this.Jsonp(result);
}
public IQueryable<User> GetAllUsersByIds(List<int> ids)
{
return _db.Users.Where(c=> ids.Contains(c.Id));
}
Then you just call the GetUsers function via a regular AJAX function supplying the array of Ids(in this case I am using jQuery stringify to send the array as string and dematerialize it back in the controller but you can just send the array of ints and receive it as an array of int's in the controller). I've build an entire Restful API using ASP.NET MVC that returns the data as cross domain json and that can be used from any app. That of course if you can use ASP.NET MVC.
function GetUsers()
{
var link = '<%= ResolveUrl("~")%>users?callback=?';
var userIds = [];
$('#multiselect :selected').each(function (i, selected) {
userIds[i] = $(selected).val();
});
$.ajax({
url: link,
traditional: true,
data: { 'userIds': JSON.stringify(userIds) },
dataType: "jsonp",
jsonpCallback: "refreshUsers"
});
}