Trying to respond to Slack depending on response other API - asynchronous

I'm have difficulties of responding to Slack using Node Red. The response should wait on the response of another REST call.
I guess I need something with async await? But I can't figure out how to create the flow.
This is how the process should work
sent an interactive message to Slack
User clicks on a button (decline or Approve)
message is sent to Slack that request is being processed in other system
the request is transformed and posted to an other API /other system
When the response is received, then it should send the response back to Slack.
Can someone help me on this? (I'm trying to learn Node Red)
The nodejs that does exactly what I'm intent to do:
app.post('/review', urlencodedParser, async (req,res) => {
try{res.send(`Contract is currently being processed`)
var request = JSON.parse(req.body.payload);
var slackmessage = await SlackContractReviewContent(request);
var response = await sendContractReview(slackmessage.entity, slackmessage.status);
var Slackresponse = await sendSlackDelayedMessage(slackmessage,response);
console.log(Slackresponse);
res.end()
} catch (err) {
console.log(`Could not be processed!`);
res.end();
};

Related

Is it possible to implement an auto logout feature for inactivity?

I am trying to implement the auto logout feature after x mins of inactivity on flutter while using Firebase , authentication method being email.
I have searched online but whatever I've found is not for flutter.
Any help will be greatly appreciated thank you!
you can use interceptor for all api instance like this, but instead customize the onRequest method.
the idea is: save time information when hit api occurred. and then whenever another hit api occur, check duration between now and last saved time.
if the duration is longer than, let's say 5 minutes, then you can call method logout, else you can continue the request
here some snippet to make it clear:
Future<Dio> getApiClient() async {
_dio.interceptors.clear();
_dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) {
// Do something before request is sent
var pref = await SharedPreferences.getInstance();
var timeNow = DateTime.now().millisecondsSinceEpoch;
var lastHitApi = pref.getInt(LAST_HIT_API);
var delay = timeNow - lastHitApi;
pref.setInt(LAST_HIT_API, timeNow);
if (delay > DELAY_MAX) {
// do logout here
}
return options;
},onResponse:(Response response) {
// Do something with response data
return response; // continue
}, onError: (DioError error) async {
// Do something with response error
}));
_dio.options.baseUrl = baseUrl;
return _dio;
}
Edit: i guess this one is more preferable
Set the timeout duration and call logout funtion
Timer(Duration(seconds: 5), () => logOut());

Change the HTTP status code with a Google Cloud Function Promise

My code checks if a user is authorized, if the user is, the proper code is run. If the user is not, it run reject() to reject the promise.
If I run the code authenticated, I get
{"error":{"status":"INVALID_ARGUMENT","message":"Bad Request"}}
I am trying to change the status code to Forbidden (code 403) which you would normally do with res.status(403) however since this is a promise it is different. How can I change the error code returned?
My code is as follows:
const cloudFunction = functions.https.onCall((data, context) => {
return new Promise(function(resolve, reject) {
auth.verifyIdToken(data.userId).then(function(decodedToken) {
if(claims.admin === true) {
// Run code if user has admin role
}
else {
reject()
// Return error code 403 because user does not have admin role
}
}).catch(err => reject(err)) // Return error code 401 because user is not logged in
})
});
You can't change the HTTP status for a callable function. Callable functions essentially take over and hide the HTTP protocol for the request and response. All you do is specify the input and output objects, and the SDKs handle everything else.
If you need to control the HTTP status of a response, you will have to use a regular HTTP type function instead. Then you will have full control over the request and response.

Koa SSE "write after end"

I have been trying to implement an SSE stream with Koa for hours now but got the following error when trying to send a message to my client after initializing the connection.
Error [ERR_STREAM_WRITE_AFTER_END]: write after end
Here's how I set up my SSE:
Client-side:
const source = new EventSource("http://localhost:8080/stream");
this.source.onmessage = (e) => {
console.log("---- RECEIVED MESSAGE: ", e.data);
};
// Catches errors
this.source.onerror = (e) => {
console.log("---- ERROR: ", e.data);
};
Server-side (Koa):
// Entry point to our SSE stream
router.get('/stream', ctx => {
// Set response status, type and headers
ctx.response.status = 200;
ctx.response.type = 'text/event-stream';
ctx.response.set({
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
});
// Called when another route is reached
// Should send to the client the following
ctx.app.on('message', data => {
ctx.res.write(`event: Test\n`);
ctx.res.write(`data: This is test data\n\n`);
});
});
The error comes when we call ctx.res.write once a message is received.
Why is my stream ended although nothing explicitly is doing it?
How may I send a message through the stream with Koa?
Koa is entirely promise based and everything is a middleware.
Every middleware returns a promise (or nothing). The middleware chain is effectively 'awaited' and once the middleware returns, Koa knows the response is done and will end the stream.
To make sure that Koa doesn't do this, you have to make sure that the chain of middlewares don't end. To do this, you need to return a promise that only resolves when you're done streaming.
A quick hack to demonstrate would be to return a promise that doesn't resolve:
return new Promise( resolve => { }});

Parse Server Cloud code keeps sending push notifications

I've developed an app that sends push notifications using Parse Server Cloud code. These notifications are received correctly in the devices but hours later they are automatically sent from Parse Server again (and they are received again). This happens 3 or 4 times for each push notifications.
If push notifications are sent from Parse Dashboard they are only sent once, so it seems it's a problem of my cloud code.
This is my code:
Parse.Cloud.define("sendPushNotification", function(request, response) {
var userId = request.params.userId;
var message = request.params.message;
var queryUser = new Parse.Query(Parse.User);
queryUser.equalTo('objectId', userId);
var query = new Parse.Query(Parse.Installation);
query.matchesQuery('user', queryUser);
Parse.Push.send({
where: query,
data: {
alert: message,
badge: 0,
sound: 'default'
}
}, {
success: function() {
console.log('##### PUSH OK');
response.success();
},
error: function(error) {
console.log('##### PUSH ERROR');
response.error('ERROR');
},
useMasterKey: true
});
});
I had a similar issue sending emails from another cloud code function (not included in the question) and my problem was because I forgot to add response.success(); and response.error('ERROR'); methods.
So this time I was sure to include these 2 calls in the responses of "sendPushNotification" method.
After sending a push notification the logs show this:
2017-07-09T15:38:02.427Z - Ran cloud function sendPushNotification for user undefined with:
Input: {"message":"This is my message","userId":"myUserIdInParse"}
Result: undefined
I think that this "Result: undefined" could be related with the problem because success and error functions are not called.
What could be the problem with this code? Why the code doesn't receive a success() when the notifications are received correctly in the devices?

Google Calendar API watch channels not stopping

Stopping a watch channel is not working, though it's not responding with an error, even after allowing for propagation overnight.  I'm still receiving 5 notifications for one calendarlist change.  Sometimes 6.  Sometimes 3.  It's sporadic. We're also receiving a second round of notifications for the same action after 8 seconds.  Sometimes 6 seconds.  Sometimes a third set with a random count.  Also sporadic. Received a total of 10 unique messages for a single calendar created via web browser.
You can perform infinite amount of watch requests on specific calendar resource, Google will always return the same calendar resource Id for the same calendar, but the uuid you generate in the request will be different, and because of that, you will receive multiple notifications for each watch request that you've made. One way to stop all notifications from specific calendar resource, is to listen for notifications, pull out "x-goog-channel-id" and "x-goog-resource-id" from notification headers, and use them in Channels.stop request.
{
"id": string,
"resourceId": string
}
Every time you perform a watch request, you should persist the data from the response, and check if the uuid or resource id already exist, if yes don't perform watch request for that resource id again (if you don't want to receive multiple notifications).
e.g.
app.post("/calendar/listen", async function (req, res) {
var pushNotification = req.headers;
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.end("Post recieved");
var userData = await dynamoDB.getSignInData(pushNotification["x-goog-channel-token"]).catch(function (err) {
console.log("Promise rejected: " + err);
});
if (!userData) {
console.log("User data not found in the database");
} else {
if (!userData.calendar) {
console.log("Calendar token not found in the user data object, can't perform Calendar API calls");
} else {
oauth2client.credentials = userData.calendar;
await calendarManager.stopWatching(oauth2client, pushNotification["x-goog-channel-id"], pushNotification["x-goog-resource-id"])
}
}
};
calendarManager.js
module.exports.stopWatching = function (oauth2client, channelId, resourceId) {
return new Promise(function (resolve, reject) {
calendar.channels.stop({
auth: oauth2client,
resource: {
id: channelId,
resourceId: resourceId
}
}, async function (err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return reject(err);
} else {
console.log("Stopped watching channel " + channelId);
await dynamoDB.deleteWatchData(channelId)
resolve(response);
}
})
})
}
Not a google expert but I recently implement it in my application,
I am trying to answer some of your questions for future readers:
It's sporadic
Tha's because you have create more than 1 channels for watching events.
We're also receiving a second round of notifications for the same action after 8 seconds
Google doesn't say anything about the maximum delay for sending a push notification.
Suggestions:
CREATE:
When you create a new channel, always save the channel_id and channel_resource in your database.
DELETE:
When you want to delete a channel just use stop API endpoint with the channel data saved in your database
RENEW:
As you have noticed the channels do expire, so you need to update them once in a while. To do that create a crone in your server that is going to STOP all previous channels and it will create new one.
Comment: Whenever something is going wrong please read the error message sent from the Google API calendar. Most of the time, it tells you what is wrong.
Use Channels.stop which is mentioned in the docs. Supply the following data in your request body:
{
"id": string,
"resourceId": string
}
id is the channel ID when you created your watch request. Same goes with resource ID.
Read this SO thread and this github forum for additional reference.

Resources