How to set multiple values in Slack cursor Parameter - slack-api

In the Slack API End point URL, I used the cursor fields and I got all the public channels. But I am unable to set all the below curson values in the End point URL.
Could you please advise me how I can set these multiple cursor values in a parameter ""cursor ?
Please find below the End point URL :
req.setEndpoint('https://slack.com/api/conversations.list?limit=999&types=public_channel&exclude_archived=true&cursor=dGVhbTpDRjBDOUdWUk4=&cursor=dGVhbTpDMDFGMlFNR0g4Qw==&cursor=dGVhbTpDMDFTV0hOTDM0NA==');
Here is the cursor values :
dGVhbTpDRjBDOUdWUk4=
dGVhbTpDMDFGMlFNR0g4Qw==
dGVhbTpDMDFTV0hOTDM0NA==
dGVhbTpDMDIwSFFRSzlHUQ==
dGVhbTpDMDIzTkIwQ0FDQg==
dGVhbTpDMDI2TkVCUEU3Mg==
dGVhbTpDMDI5SzFZUzNVSA==
dGVhbTpDMDJERUJDQTVBTQ==
dGVhbTpDMDJGV1M3QUtGRw==
dGVhbTpDMDJKNUhaVVNOOA==
dGVhbTpDMDJMUzFLVjNQRg==
dGVhbTpDMDJQRDhZQjBQSg==
dGVhbTpDMDJTSkVLUTlQVg==
dGVhbTpDMDMwME1DMTdKVA==
dGVhbTpDMDMyTENESEE3Nw==
dGVhbTpDMDM1Rjg5NTJVVw==
dGVhbTpDMDM4QlNYQVQ4Vw==
dGVhbTpDMDNCOE5HQ01CUA==
ZXh0ZXJuYWw6QzAySFFLOFBCNUU=
Thanks !!

cursor parameter is used for paginating the data fetched using given API.
Each cursor value points to the next page of data.
You need to iteratively call the API (adding the received cursor value from each request) and store each response, till the cursor value becomes blank.
Best approach will be to implement a Do...While loop, where while condition will be cursor != ""
Sample Code:
var channelRecords = []
var nextCursor = ''
do{
await axios.get(`https://slack.com/api/conversations.list?limit=999&types=public_channel&exclude_archived=true&${(nextCursor == '') ? '': `&cursor=${nextCursor}`}`,{
headers: {
'Authorization': `Bearer ${SLACK_USER_TOKEN}`
}})
.then(response => {
if (response.status == 200)
{
channelRecords = channelRecords.concat(response.data.channels)
}
nextCursor = response.data.response_metadata.next_cursor
})
.catch(error => {
console.log(error);
});
}while (nextCursor != '')
//This code does not take care of API's rate limit
You can also use Slack's Bolt framework and their sample code:
https://api.slack.com/methods/conversations.list/code

Related

Pagination - How can I store and provide a non-numeric page identifier?

I am trying to add pagination to my Zapier trigger.
The API I am using for the trigger supports pagination, but not using a page number in the traditional sense (ie. page 1,2,3,...). Instead, the API response includes a key (ie. "q1w2e3r4") which should be passed as a parameter to the next request to get the next page of results.
From looking at the docs, I can use {{bundle.meta.page}} (which defaults to 0 unless otherwise set).
I am trying to set {{bundle.meta.page}} in the code editor, with an example shown below:
const options = {
url: 'company_xyz.com/api/widgets',
method: 'GET',
...,
params: {
...,
'pagination_key': bundle.meta.page,
}
}
return z.request(options)
.then((response) => {
response.throwForStatus();
const json_response = response.json;
widgets = json_response.widgets
...
bundle.meta.page = json_response["next_pagination_key"]
return widgets;
});
The problem is that when Zapier tries to retrieve the next page, bundle.meta.page will be 1 instead of the value of "next_pagination_key" from the result of the previous request.
There are docs on cursor-based pagination in the CLI docs.
The relevant block is:
const performWithAsync = async (z, bundle) => {
let cursor;
if (bundle.meta.page) {
cursor = await z.cursor.get(); // string | null
}
const response = await z.request(
'https://5ae7ad3547436a00143e104d.mockapi.io/api/recipes',
{
// if cursor is null, it's sent as an empty query
// param and should be ignored by the server
params: { cursor: cursor }
}
);
// we successfully got page 1, should store the cursor in case the user wants page 2
await z.cursor.set(response.nextPage);
return response.items;
};
This should work in the Zapier Visual Builder, but you might need to use the CLI instead. You can export your integration using the zapier convert CLI command (docs).

How to dispatch a Paypal IPN to a Google Cloud function?

I've read here that it's possible to send an IPN directly to a Google cloud function. I have my Google Cloud functions running on Firebase on an index.js file.
I've set up my Paypal buttons to send the IPN to a page on my webapp.
Here is an example of one of the functions I'm running off Google Cloud Functions/Firebase:
// UPDATE ROOMS INS/OUTS
exports.updateRoomIns = functions.database.ref('/doors/{MACaddress}').onWrite((change, context) => {
const beforeData = change.before.val();
const afterData = change.after.val();
const roomPushKey = afterData.inRoom;
const insbefore = beforeData.ins;
const insafter = afterData.ins;
if ((insbefore === null || insbefore === undefined) && (insafter === null || insafter === undefined) || insbefore === insafter) {
return 0;
} else {
const updates = {};
Object.keys(insafter).forEach(key => {
updates['/rooms/' + roomPushKey + '/ins/' + key] = true;
});
return admin.database().ref().update(updates); // do the update}
}
return 0;
});
Now question:
1) I want to add another function to process IPN from Paypal as soon as I have a transaction. How would I go about this?
I'll mark the answer as correct if solves this first question.
2) how would that Google cloud function even look like?
I'll create another question if you can solve this one.
Note I am using Firebase (no other databases nor PHP).
IPN is simply a server that tries to reach a given endpoint.
First, you have to make sure that your firebase plan supports 3rd party requests (it's unavailable in the free plan).
After that, you need to make an http endpoint, like so:
exports.ipn = functions.http.onRequest((req, res) => {
// req and res are instances of req and res of Express.js
// You can validate the request and update your database accordingly.
});
It will be available in https://www.YOUR-FIREBASE-DOMAIN.com/ipn
Based on #Eliya Cohen answer:
on your firebase functions create a function such as:
exports.ipn = functions.https.onRequest((req, res) => {
var reqBody = req.body;
console.log(reqBody);
// do something else with the req.body i.e: updating a firebase node with some of that info
res.sendStatus(200);
});
When you deploy your functions go to your firebase console project and check your functions. You should have something like this:
Copy that url, go to paypal, edit the button that's triggering the purchase, scroll down to Step 3 and at the bottom type:
notify_url= paste that url here
Save changes.
You can now test your button and check the req.body on your firebase cloud functions Log tab.
Thanks to the answers here, and especially to this gist: https://gist.github.com/dsternlicht/fdef0c57f2f2561f2c6c477f81fa348e,
.. finally worked out a solution to verify the IPN request in a cloud func:
let CONFIRM_URL_SANDBOX = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
exports.ipn = functions.https.onRequest((req, res) => {
let body = req.body;
logr.debug('body: ' + StringUtil.toStr(body));
let postreq = 'cmd=_notify-validate';
// Iterate the original request payload object
// and prepend its keys and values to the post string
Object.keys(body).map((key) => {
postreq = `${postreq}&${key}=${body[key]}`;
return key;
});
let request = require('request');
let options = {
method: 'POST',
uri : CONFIRM_URL_SANDBOX,
headers: {
'Content-Length': postreq.length,
},
encoding: 'utf-8',
body: postreq
};
res.sendStatus(200);
return new Promise((resolve, reject) => {
// Make a post request to PayPal
return request(options, (error, response, resBody) => {
if (error || response.statusCode !== 200) {
reject(new Error(error));
return;
}
let bodyResult = resBody.substring(0, 8);
logr.debug('bodyResult: ' + bodyResult);
// Validate the response from PayPal and resolve / reject the promise.
if (resBody.substring(0, 8) === 'VERIFIED') {
return resolve(true);
} else if (resBody.substring(0, 7) === 'INVALID') {
return reject(new Error('IPN Message is invalid.'));
} else {
return reject(new Error('Unexpected response body.'));
}
});
});
});
Also thanks to:
https://developer.paypal.com/docs/classic/ipn/ht-ipn/#do-it
IPN listener request-response flow: https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/
To receive IPN message data from PayPal, your listener must follow this request-response flow:
Your listener listens for the HTTPS POST IPN messages that PayPal sends with each event.
After receiving the IPN message from PayPal, your listener returns an empty HTTP 200 response to PayPal. Otherwise, PayPal resends the IPN message.
Your listener sends the complete message back to PayPal using HTTPS POST.
Prefix the returned message with the cmd=_notify-validate variable, but do not change the message fields, the order of the fields, or the character encoding from the original message.
Extremely late to the party but for anyone still looking for this, PayPal have made a sample in their JS folder on their IPN samples Github repo.
You can find this at:
https://github.com/paypal/ipn-code-samples/blob/master/javascript/googlecloudfunctions.js

Zapier JS Action to Fetch Klout Scores

I'm trying to create a Java Script Code Action on Zapier to fetch Klout Scores for any given Twitter user name...
I've realized that this needs to be done in 2 stages:
1) First get the Klout ID for any Twitter screen_name:
http://api.klout.com/v2/identity.json/twitter?screenName="+screen_name+"&key="+klout_apikey"
Klout replies back to that with JSon:
{"id":"85568398087870011","network":"ks"}
2) second get the Klout score for that Klout id:
http://api.klout.com/v2/user.json/"+klout.id+"/score?key="+klout_apikey"
Klout replies back to this with JSon:
{"score":65.68382904221806,"scoreDelta":{"dayChange":-0.03663891859041257,"weekChange":-0.5495711661078815,"monthChange":-1.4045672671990417},"bucket":"60-69"}
Of course, what I need is the "score":65.68382904221806 object of the JSon reply array.
I use these following JS functions proposed by #KayCee:
var klout_apikey = '<my klout api key>';
fetch("http://api.klout.com/v2/identity.json/twitter?screenName="+screen_name+"&key="+klout_apikey")
.then(function(res) {
return res.json();
})
.then(function(klout) {
console.log(klout);
if(klout.id) {
return fetch("http://api.klout.com/v2/user.json/"+klout.id+"/score?key="+klout_apikey")
}
}).then(function(res) {
return res.json();
}).then(function(body) {
// console.log(body.score);
//Here is where you are telling Zapier what you want to output.
callback(null, body.score)
}).catch(callback); //Required by Zapier for all asynchronous functions.
In the "input data" section of the Zapier code action i pass the screen_name as a variable:
screen_name: [the twitter handle]
What I get back is the following error message:
SyntaxError: Invalid or unexpected token
What is the error that you see? You could do this by simply using the fetch client. You might want to remove the variable declarations before adding this to the code step.
var inputData = {'screen_name': 'jtimberlake'}
//Remove the line above before pasting in the Code step. You will need to configure it in the Zap.
var klout_apikey = '2gm5rt3hsdsdrzgvnskmgm'; //Not a real key
fetch("http://api.klout.com/v2/identity.json/twitter?screenName="+inputData.screen_name+"&key="+klout_apikey)
.then(function(res) {
return res.json();
})
.then(function(body) {
console.log(body);
if(body.id) {
return fetch("http://api.klout.com/v2/user.json/"+body.id+"/score?key="+klout_apikey)
}
}).then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
//Here is where you are telling Zapier what you want to output.
callback(null, body)
}).catch(callback); //Required by Zapier for all asynchronous functions.
Refer to their documentation here - https://zapier.com/help/code/#introductory-http-example
Also refer to their Store client which allows you to store values (for cache) - https://zapier.com/help/code/#storeclient-javascript

Is it possible to post data to couch db and return data?

For example I would like to send the users score to the database and instead of it returning the typical status, id and rev I would like it to return the users rank. I'm guessing this isn't possible but figured I would ask.
The response to an HTTP POST/PUT should really only be used to help you confirm that it succeeded.
I'm even struggling to see even how you can get the rank of a user returned by a couchdb view, unless you retrieve the data for all users and work out the position of your user.
This use case ...
Simple structured data clearly tabular
The requirement to respond fast to a numerical column (Method to calculate the rank for a score)
OR the requirement to trigger an update a score table each time a rank is submitted.
... very much smells like a classical case where you may want to use a relational DB.
If the result can be calculated from the document you are to change with your http request, then you can use an update handler to PUT a change to the document and return that result:
// 'myhandler' update function
function(doc, req) {
// create a shorthand for json reponses
var json_reponse = function(obj, code) {
return {
headers: { 'Content-Type': 'application/json' }
, body: JSON.stringify(obj)
, code: code
}
}
// assume the incoming body is json and parse it
// needs proper error handling still
var body = JSON.parse(req.body)
// doc is the user document we are patching
// return an error if it isn't there
if(!doc)
return [null, json_response({error: 'user document not found'}, 404)]
// return an error if new_score is missing from body
if(!body.new_score)
return [null, json_response({error: 'missing property new_score'}, 400)
// now patch the user doc
doc.score = body.new_score
// calculate the new rank depending on your own method
var my_rank = my_rank_function(doc.score, Math.PI, 'bananarama')
return [doc, json_response({success: true, rank: my_rank}, 200)
}
Now PUT new data to receive the new rank:
request(
{ method: 'PUT'
, url: httptp://127.0.0.1:5984/mydb/_design/myddoc/_update/myhandler/myuserdocid
, json: {"new_score": 42}
, headers: { "Content-Type: application/json" }
}
, function(err, response, body) {
console.log("user's new rank:", JSON.parse(body).rank)
}
)
should print user's new rank: LEVEL 11 EIGHTIES GIRL GROUP LEADER
nb: I'm not at work so cannot confirm the code works, but you should get the hang of it...

Why i don't see my #replies in conversation view in twitter?

I need to reply to one particular twitter status. I'm using following functions. And I've used Abraham's twitteroauth library in php.
public function replyToTwitterStatus($user_id,$status_id,$twitt_reply,$account_name)
{
$connection= $this->getTwitterConnection($user_id,$account_name);
try{
$responce = $this->postApiData('statuses/update', array('status' => $twitt_reply,'in_reply_to_status_id '=> $status_id),$connection);
}
catch(Exception $e){
echo $message = $e->getMessage();
exit;
}
}
// this function will handle all post requests
// To post/update twitter data
// To post/update twitter data
public function postApiData($request,$params = array(),$connection)
{
if($params == null)
{
$data = $connection->post($request);
}
else
{
$data = $connection->post($request,$params);
}
// Need to check the error code for post method
if($data->errors['0']->code == '88' || $data->errors['0']->message == 'Rate limit exceeded')
{
throw new Exception( 'Sorry for the inconvenience,Please wait for minimum 15 mins. You exceeded the rate limit');
}
else
{
return $data;
}
}
But the issue is that it is not maintaining the conversation view and it is update like normal status for e.g #abraham hello how are you. but that "View conversation" is not coming. Like expanding menu is not coming.
Please do needful
Thanks
You've got an unwanted space in your in_reply_to_status_id key which causes that parameter to be ignored.
This call:
$responce = $this->postApiData('statuses/update', array(
'status' => $twitt_reply,
'in_reply_to_status_id ' => $status_id
), $connection);
should look like this:
$responce = $this->postApiData('statuses/update', array(
'status' => $twitt_reply,
'in_reply_to_status_id' => $status_id
), $connection);
Also, make sure that the $status_id variable is being handled as a string. Although they look like numbers, most ids will be too big to be represented as integers in php, so they'll end up being converted to floating point which isn't going to work.
Lastly, make sure you have include the username of the person you are replying to in the status text. Quoting from the documentation for the in_reply_to_status_id parameter:
Note:: This parameter will be ignored unless the author of the tweet this parameter references is mentioned within the status text. Therefore, you must include #username, where username is the author of the referenced tweet, within the update.

Resources