How to upload file to Object Storage in Bluemix (by nodejs) - node.js

I am trying to use the Object Storage Service at IBM Bluemix Cloud, but I can't send images from my nodejs server. How can I do this? Follow my server code:
unirest
.post(MY_CONTAINER + new_fname)
.headers({'Content-Type': 'multipart/form-data', 'X-Auth-Token': token})
.field({ 'max_file_count': 1 })
.field({ 'max_file_size': 1 })
.attach({ 'file': file.originalname, 'relative file': streamFile })
.end(function (resp) {
//response
console.log(resp.status);
console.log(resp.body);
});
The main problem is to find the right way to send an image (png or jpg) to the bluemix storage using the API (I've aready uploaded it to our server).

I used the pkgcloud-bluemix-objectstorage to fix the OpenStack authentication bug that previously used the v2 and has been changed to use the v3.
here's the link
Bluemix - object storage - node.js - pkgcloud - openstack returns 401
the #libik writes an example.
var pkgcloud = require('pkgcloud-bluemix-objectstorage');
var fs = require('fs');
// Create a config object
var config = {};
// Specify Openstack as the provider
config.provider = "openstack";
// Authentication url
config.authUrl = 'https://identity.open.softlayer.com/';
config.region= 'dallas';
// Use the service catalog
config.useServiceCatalog = true;
// true for applications running inside Bluemix, otherwise false
config.useInternal = false;
// projectId as provided in your Service Credentials
config.tenantId = '234567890-0987654';
// userId as provided in your Service Credentials
config.userId = '098765434567890';
// username as provided in your Service Credentials
config.username = 'admin_34567890-09876543';
// password as provided in your Service Credentials
config.password = 'sdfghjklkjhgfds';
**//This is part which is NOT in original pkgcloud. This is how it works with newest version of bluemix and pkgcloud at 22.12.2015.
//In reality, anything you put in this config.auth will be send in body to server, so if you need change anything to make it work, you can. PS : Yes, these are the same credentials as you put to config before.
//I do not fill this automatically to make it transparent.
config.auth = {
forceUri : "https://identity.open.softlayer.com/v3/auth/tokens", //force uri to v3, usually you take the baseurl for authentication and add this to it /v3/auth/tokens (at least in bluemix)
interfaceName : "public", //use public for apps outside bluemix and internal for apps inside bluemix. There is also admin interface, I personally do not know, what it is for.
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"id": "098765434567890", //userId
"password": "sdfghjklkjhgfds" //userPassword
}
}
},
"scope": {
"project": {
"id": "234567890-0987654" //projectId
}
}
};**
//console.log("config: " + JSON.stringify(config));
// Create a pkgcloud storage client
var storageClient = pkgcloud.storage.createClient(config);
// Authenticate to OpenStack
storageClient.auth(function (error) {
if (error) {
console.error("storageClient.auth() : error creating storage client: ", error);
} else {
//OK
var new_fname = dir + "__" + file.originalname;
var readStream = fs.createReadStream('uploads/' + file.filename);
var writeStream = storageClient.upload({
container: 'chat-files',
remote: new_fname
});
writeStream.on('error', function(err) {
// handle your error case
console.log("concluido o upload com erro!");
console.log(err);
});
writeStream.on('success', function(file) {
// success, file will be a File model
console.log("concluido o upload com sucesso!");
});
readStream.pipe(writeStream);
}
});

#JeffSloyer wrote a Node.js sample application to upload files to an Object Storage instance in Bluemix.
You can find the code here:
https://github.com/IBM-Bluemix/node-file-upload-swift
The code above fails to authenticate using Open Stack Swift v3, so I made a modification to the skipper-openstack module to use pkgcloud-bluemix-objectstorage:
https://github.com/adasilva70/skipper-openstack.git#adasilva70-patch-1
Clone Jeff's repository and follow the instructions in the README.md file to run the code. Make sure you modify the package.json file with the one below to get my changes:
{
"name": "node-file-upload-swift",
"version": "0.0.0",
"dependencies": {
"bower": "^1.7.1",
"cf-deployment-tracker-client": "*",
"cfenv": "^1.0.3",
"dotenv": "^1.2.0",
"express": "~4.x",
"skipper": "^0.5.8",
"skipper-openstack": "git+https://github.com/adasilva70/skipper-openstack.git#adasilva70-patch-1",
"stream": "0.0.2",
"underscore": "^1.8.3"
},
"main": "server.js",
"scripts": {
"start": "node server.js",
"postinstall": "bower install --allow-root --config.interactive=false"
}
}

Related

Can data be retrieved from the Google Fitness REST API using a JWT token to authenticate?

Apologies for my previous badly formulated question.
I am trying to write a standalone NodeJS app, that retrieves activity data from the Google Fit REST API and writes it locally as a json file. The app will run unattended on a headless raspberry pi, so there are no "browser pop-up" windows in order to authenticate with a Google account.
I activated my Google Fit API and created service account credentials. My key is stored as MY_KEY.json in this example. Now using the googleapis library, I create a JWT token signed with MY_KEY.json, and authenticate with it when sending my request.
I get a response from the API, but the data is empty. (I know there is data, since doing a similar request in a browser with a traditional oauth2 flow returns all my activity data sessions. I wonder if authentication with JWT tokens using a service account is allowed for fitness data ?
Here is my code :
'use strict';
const {google, fitness_v1} = require('googleapis');
const path = require('path');
const fs = require('fs');
async function runSample() {
// Create a new JWT client using the key file downloaded from the Google Developer Console
const auth = new google.auth.GoogleAuth({
keyFile: path.join(__dirname, 'MY_KEY.json'),
scopes: 'https://www.googleapis.com/auth/fitness.activity.read',
});
const client = await auth.getClient();
// Obtain a new fitness client, making sure you pass along the auth client
const fitness_v1 = google.fitness({
version: 'v1',
auth: client
});
//console.log(client);
const res = await fitness_v1.users.sessions.list({
"userId": "me"
});
fs.writeFile('session.json', JSON.stringify(res.data, null, 4), (err) => {
if (err) {
throw err;
}
console.log("Retrieved sessions are saved as JSON.");
});
console.log(res.data);
return res.data;
}
if (module === require.main) {
runSample().catch(console.error);
}
// Exports for unit testing purposes
module.exports = {runSample};
The response is :
{
session: [],
deletedSession: [],
nextPageToken: 'XmRh96blablablan4yFjZQ'
}
It should be :
{
"session": [
{
"id": "healthkit-D7B3AC93-3739-4E04-978A-C53599D8401E",
"name": "Uni",
"description": "",
"startTimeMillis": "1645651234280",
"endTimeMillis": "1645676584280",
"modifiedTimeMillis": "1645676989684",
"application": {
"packageName": "com.apple.workout",
"version": "",
"detailsUrl": ""
},
"activityType": 72
},
{
"id": "healthkit-3691B45B-9D51-4C14-ACC6-EC9DB48B5F23",
"name": "Juoksu",
"description": "",
"startTimeMillis": "1647073527249",
"endTimeMillis": "1647075778248",
"modifiedTimeMillis": "1647076769108",
"application": {
"packageName": "runkeeperpro",
"version": "",
"detailsUrl": ""
},
"activityType": 56
}
],
"deletedSession": [],
"nextPageToken": "XmRh96blablablan4yFjZQ"
}
Any suggestions ? Thanks in advance.
According to Addendum: Service account authorization without OAuth:
With some Google APIs, you can make authorized API calls using a signed JWT directly as a bearer token, rather than an OAuth 2.0 access token. (snip)
If the API you want to call has a service definition published in the Google APIs GitHub repository, you can make authorized API calls using a JWT instead of an access token.
There is no such service definition for Fit, so, unfortunately, the answer is that you can't use JWT.

Webhooks Directus 9 - send an email when user create a record in a table

I created the "mission" collection. I want to send an email to a personalized recipient for each new recording on the mission table.
According to the Directus documentation, I saw that this is possible via webHooks.
enter link description here
However, I don't quite understand the logic. Especially since in the Directus administration interface, there is a page to add webhooks and link them to the collection concerned.
Can you tell me where I should start to achieve my POC.
I also put some screenshots on the architecture of my app, you can tell me if this is really how it should be or not. I have doubts.
{
"name": "test1-directus",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "directus start"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"directus": "^9.0.0-rc.91",
"mysql": "^2.18.1",
"nodemailer": "^6.6.3"
}
}
I created a project with the command: npx create-directus-project test1directus
My project is running on port 8055 with a reverse proxy setting on nginx.
Is everything OK or did I miss a step?
Thank you in advance for your help.
I found this example to put in: extensions / hooks / sync-with-external / index.js
After several modifications, this error persists on my writing:
An error was thrown while executing hook "items.create"
Cannot destructure property 'mission' of 'undefined' as it is undefined.
The console.log doesn't show me anything.
const axios = require("axios");
module.exports = function registerHook({ services, exceptions }) {
const { MailService } = services;
const { ServiceUnavailableException, ForbiddenException } = exceptions;
return {
// Force everything to be admin-only at all times
"items.*": async function ({ item, accountability }) {
if (accountability.admin !== true) throw new ForbiddenException();
},
// Sync with external recipes service, cancel creation on failure
"items.create": async function (input, { mission, schema }) {
console.log(items);
if (mission !== "recipes") return input;
const mailService = new MailService({ schema });
try {
await axios.post("https://example.com/items", input);
await mailService.send({
to: "pseudo.pseudo#gmail.com",
template: {
name: "item-created",
data: {
collection: mission,
},
},
});
} catch (error) {
throw new ServiceUnavailableException(error);
}
input[0].syncedWithExample = true;
return input;
},
};
};
You can now use Directus Flows from Settings > Flows.
Read the docs here: https://docs.directus.io/configuration/flows

I can not get information with "DialogflowApp.getUser" method

https://developers.google.com/actions/reference/nodejs/ApiAiApp
I'd like to obtain an access token on Dialogflow by referring to the above official website, but the execution result of DialogflowApp.getUser() will be null.
Account linking is set up and on the client side it is certified with a Google Account.
AssistantToAgentDebug.assistantToAgentJson.user on the DEBUG tab of DialogFlow Simulator contains a value.
Also, I can get an access token by referring req.body.originalRequest.data.user.accessToken variable on the request body.
I'd like to obtain user information with DialogflowApp.getUser(),
Is there a mistake in the definition below?
*Using the Fullfilment, the logic is described in index.js.
*index.js
'use strict';
const App = require('actions-on-google').DialogflowApp;
exports.testMethod = (req, res) => {
// result is null
const app = new App({req, res});
let user = app.getUser();
console.log('User is ' + user);
// Access token can be acquired
let accessToken = req.body.originalRequest.data.user.accessToken;
console.log('accessToken is ' + accessToken);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'speech': 'success!', 'displayText': 'success!' }));
};
*package.json
{
"name": "testMethod",
"engines": {
"node": "~4.2"
},
"dependencies": {
"actions-on-google": "^1.0.0",
"firebase-admin": "^4.2.1",
"firebase-functions": "^0.5.7"
}
}
The problem is that the call to the constructor expect the parameters to be named request and response. So you should write the line as
const app = new App({request:req, response:res});
You need to use getUser().accesToken like this:
let accestoken = app.getUser().accessToken;

heroku server and firebase

I am trying to make a server that listens to changes made in the firebase database and then sends an email to some email address. I manage to implement firebase and sendgrid, I already tested by adding some entry to the database and also sending a test mail. So sendgrid and firebase are working. The problem here relies on how I manage to send the emails, every time I open the app it sends the email.
So here comes the issue, If every time the apps opens it executes the code in the js file. When I add the code to listen to a child added event in the database it will get called every time I open the app, so multiple listener will be active and I assume multiple emails will be send regarding one single event.
So I'm clueless , is there anyway that this is only called once? or I should not open the "app" more than one time? or am I not deploying the server the right way?
My objective is that once I deploy the server it will automatically do whats its written, without the need to actually open the "app" in heroku, or at least that when the app is open the code do not get called again, just once when deployed.
Here is the code for the server.js
var firebase = require('firebase');
var helper = require('sendgrid').mail;
firebase.initializeApp({
serviceAccount: "./DB-A2312SDA.json",
databaseURL: "https://DATABASENAME.firebaseio.com/"
});
// Email
var from_email = new helper.Email('example#example.com');
var to_email = new helper.Email('example#gmail.com');
var subject = 'Hello World from the SendGrid Node.js Library!';
var content = new helper.Content('text/plain', 'Hello, Email!');
var mail = new helper.Mail(from_email, subject, to_email, content);
var sg = require('sendgrid')(process.env.SG_API_KEY);
var request = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: mail.toJSON(),
});
sg.API(request, function(error, response) {
console.log(response.statusCode);
console.log(response.body);
console.log(response.headers);
});
This is the package.json
{
"name": "server_test",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"engines": {
"node": "6.9.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"firebase": "^3.5.1",
"sendgrid": "^4.7.0"
}
}
and the procfile
web: node server.js
Typically in such a scenario you'll have a node in your database that indicates the addresses that you need to send a message to. For example, if you want to send a welcome message to people that have signed up for something, you could model that as:
welcomeMessageQueue
$pushid
email: "rialcom#company.com"
firstName: "Ralcom"
Not you can attach a listener in your node script that:
for each message in this queue
sends a message to that email address
and then removes the item from the queue
The important thing here is that you remove the item from the queue once you've sent the message. That way, the message will only be sent once.
A simple way to do this would be:
var ref = firebase.database().ref();
var queue = ref.child('welcomeMessageQueue');
queue.on('child_added', function(snapshot) {
var message = snapshot.val();
var sg = require('sendgrid')(process.env.SG_API_KEY);
var request = sg.emptyRequest({
method: 'POST',
path: '/v3/mail/send',
body: mail.toJSON(),
});
sg.API(request)
.then(function(response) {
snapshot.ref.remove();
});
})
For a more scalable way to do this, have a look at firebase-queue.
For a simple tutorial that uses this approach, see this blog post on sending push notifications.

What is the best approach for Authorization with node.js and Socket.io

I have been "playing" with authentication using node.js, express and socket.io
I have tried the example here http://howtonode.org/socket-io-auth
app.use(express.cookieParser("rocks"));
app.use(express.session());
io.set('authorization', function(handshakeData, accept) {
console.log('in authorization');
if(handshakeData.headers.cookie) {
handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);
handshakeData.sessionID = connect.utils.parseSignedCookie(handshakeData.cookie['express.sid']);
if (handshakeData.cookie['express.sid'] == handshakeData.sessionID) {
return accept('Cookie is invalid.', false);
}
} else {
return accept('No cookie transmitted.', false);
}
accept(null, true);
});
I keep getting an error generated by connect, more specifically this call line
connect.utils.parseSignedCookie(handshakeData.cookie['express.sid']);
/workspace/node_modules/connect/node_modules/cookie-signature/index.js:39
if ('string' != typeof secret) throw new TypeError('secret required');
^
TypeError: secret required
I have tried to find the api documentation for express.cookieParser (which I have) and express.session (which I have not) and looked at the offending source code. I imagine there is something going on with the way I have set up the project as connect seems to have a cookieParser as well as express, or express is using the cookieParser from connect.
My package.json looks like
{
"name": "mplayer",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"socket.io":"0.9.16",
"express": "3.4.0",
"jade": "*",
"stylus": "*",
"cookie": "*"
}
}
Can someone please shed some light on why I am getting this error and secondly can someone share the most effective way of authenticating a user using Node.js, socket.io and express (I know there are various articles out there, but things seem to have moved on. It is hard to keep track of what is current).
You need to pass a secret for parsing signed cookies. This function:
connect.utils.parseSignedCookie();
Accepts two arguments, the first being req.cookies, the second being the secret. This is how you need to use the function:
var signedCookies = connect.utils.parseSignedCookie(handshake.headers.cookie, 'secret');
// signedCookies['express.sid']
The reason you're getting the error, is that you aren't passing a string as the second argument, which is what fails the typeof 'string' check.
As for the most effective way of authenticating Socket.IO users when used in conjunction with Express, it is already the way you're already using it.
var cookieParser = require('cookie-parser');
var cookie = require('cookie');
var secret = config.get('session:secret');
io.set('authorization', function(handshake, callback){
async.waterfall([
function(callback) {
handshake.cookies = cookie.parse(handshake.headers.cookie || '');
var sidCookie = handshake.cookies[config.get('session:key')];
var sid = cookieParser.signedCookie(sidCookie, secret);
}
});
https://www.npmjs.com/package/cookie-parser#cookieparser-signedcookie-str-secret-

Resources