Google storage bucket is public and still no access to files - node.js

I am creating a public bucket with nodeJS (apologise for the ES5/ES6 mix, copied Google's example were ES5):
var gcloud = require('google-cloud');
const gcs = gcloud.storage({
projectId: 'h-212f6',
keyFilename: './h-9a814129651f4.json'
});
const createBucket = (bucketName) => {
// Create a new bucket.
return new Promise((resolve, reject) => {
gcs.createBucket(bucketName, function (err, bucket) {
if (err) {
reject(err);
}
bucket.acl.add({
entity: 'allUsers',
role: gcloud.storage.acl.READER_ROLE
}, function(err, aclObject) {
console.log('err -> ', err);
});
resolve(bucket);
});
});
};
const upload = (bucket, filepath, options) => {
return new Promise((resolve, reject) => {
bucket.upload(filepath, options, function (err, file) {
if (err) {
reject(err);
}
resolve(file)
});
});
};
Yet having trouble accessing the file from Chrome:
UPDATE:
When I change the file's ACL all seems to work:
const upload = (bucket, filepath, options) => {
return new Promise((resolve, reject) => {
bucket.upload(filepath, options, function (err, file) {
if (err) {
reject(err);
}
file.acl.add({
entity: 'allUsers',
role: gcs.acl.READER_ROLE
}, function (err, aclObject) {
console.log('err -> ', err);
});
resolve(file)
});
});
};
However, I was under the assumption that changing the bucket ACL should be enough, isn't it?

When you set the ACL in your code above, you're setting it for existing objects. In order to set it as the default ACL for new objects, too, you need to do the following:
bucket.acl.default.add({
entity: 'allUsers',
role: gcloud.storage.acl.READER_ROLE
}, function(err, aclObject) {
console.log('err -> ', err);
});
See here for more examples.

Related

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'unlink' of undefined at Grid.remove

I'm trying to delete a file by its id using gridfs but I get this error when calling the delete API.
Controller :
let gfs;
connect.once("open", () => {
gfs = Grid(connect.db, mongoose.mongo);
gfs.collection("uploads");
});
exports.deleteFile = (req, res) => {
try {
gfs.remove(
{ _id: req.params.id, root: "uploads" },
(err, gridStore) => {
if (err) {
return res.status(404).send({ message: err });
} else {
return res.send({ message: "File deleted successfuly" });
}
}
);
} catch (error) {
return res.status(500).send({
message: error.message,
});
}
};
exports.deleteFileByFilename = async (req, res, next) => {
const file = await gfs.files.findOne({ filename: req.params.filename });
const gsfb = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' });
gsfb.delete(file._id, function (err, gridStore) {
if (err) return next(err);
res.status(200).end();
});
};
// #route DELETE /files/:filename
// #desc Delete file
app.delete('/files/:filename', async (req, res) => {
const file = await gfs.files.findOne({ filename: req.params.filename });
const gsfb = new mongoose.mongo.GridFSBucket(conn.db, { bucketName: 'uploads' });
gsfb.delete(file._id, function (err, gridStore) {
if (err) {
res.status(404).send('no file found')
}
res.status(200).send('deleted successfully')
});
});
On client side:
const delImage = async (fileName) => {
await axios.delete(`http://localhost:5000/files/${fileName}`);
console.log('fileDeleted');
getData(); // reminder to REFETCH the data so that database with deleted file is refreshed
}
I also made a video on this - full file uploads, multiupload, display and delete using MERN stack and NPM Multer thing, in here: https://youtu.be/4WT5nvfXcbs
Docs for the video with full code: https://docs.google.com/document/d/1MxvNNc9WdJT54TpanpFBT6o7WE_7hPAmDhdRNWE8A9k/edit?usp=sharing

export values from dynamoDB getItem

I'm trying to get data outside of the getItem function off the dynamoDB, but I'm getting this error and I don't know why.
Error ValidationException: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes
Here is my code
const aws = require("aws-sdk"),
docClient = new aws.DynamoDB.DocumentClient({ apiVersion: "2012-08-10" }),
ddb = new aws.DynamoDB({ apiVersion: "2012-08-10" }),
tableName = "usersDB",
exports.apiKey = async (req, res, context) => {
var params = {
TableName: tableName,
Key: {
"username": { "S": req.body.username },
},
ProjectionExpression: "apiKey"
};
chaveAPI = await ddb.getItem(params, function (err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
}
});
};
EDIT1: Fixed the validation error but still cannot get data from dyname. Here it is fixed
exports.apiKey = async (req, res) => {
console.log("comecei")
var params = {
TableName: tableName,
Key: {
'username': {S: req.user.username}
},
ProjectionExpression: 'apiKey'
};
// Call DynamoDB to read the item from the table
dataFromDynamo = await ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
return data.Item
}
});
console.log(dataFromDynamo)
};
A few things I notice with your code sample:
You are mixing callbacks with async/await.
You aren't declaring the dataFromDynamo variable.
Instead of this
// Call DynamoDB to read the item from the table
dataFromDynamo = await ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
console.log("Success", data.Item);
return data.Item
}
});
Do this
try {
// Call DynamoDB to read the item from the table
const dataFromDynamo = await ddb.getItem(params).promise()
console.log("Success", data.Item);
return data.Item
} catch (err) {
console.log("Error", err);
}

How to add key, value to Json data from mongoDB?

I stored product data in MongoDB and image in S3. So I'm trying to add img url to each of product data and send it together, but it doesn't work. I'm using node.js. Thanks
app.get("/products/getAllProducts", (req, res) => {
const path=[];
mongoose.model('Product').find().exec((err, productInfo) => {
if (err) return res.status(400).send(err);
productInfo.forEach(productInfo => {
s3.getSignedUrl(
"getObject",
{
Bucket: Bucket_NAME,
Key: productInfo.No+'.png'
},
(err, url) => {
if (err) {
throw err;
}
//console.log(url);
//path.push(url);
//path[productInfo.No] = url
productInfo.img = url;
//return productInfo;
}
);
})
res.status(200).json({ success: true, productInfo });
});
});

How to use google-api-nodejs-client to get a list of group members

Goal
Use googleapis to get a list of group members. Google's documentation show this:
GET https://www.googleapis.com/admin/directory/v1/groups/groupKey/members
Question
How is this done with directory.groups.get , .hasMembers, or other? I'm not sure how or where to add members to the request.
directory.groups.get({
auth: jwtClient,
domain: "mydomain.com",
groupKey: "mygroup#mydomain.com",
},
What Works
Here I get information about membership, but not the list of members
exports.getGroupsMemberships = function (jwtClient) {
return new Promise((resolve, reject) => {
jwtClient.authorize(err => {
if (err) reject(err);
else resolve();
});
}).then(() => {
return new Promise((resolve, reject) => {
directory.groups.get({
auth: jwtClient,
domain: "mydomain.com",
groupKey: "mygroup#mydomain.com",
},
function (err, resp) {
if (err) reject(err);
else resolve(resp);
});
});
});
};
which returns
"gsuiteGroupsMemberships : { kind: 'admin#directory#group',
id: 'xxx...222',
etag: '"TN3...Dw"',
email: 'mygroup#mydomain.com',
name: 'My Group',
directMembersCount: '3',
description: 'Use this email group to contact My Group.',
adminCreated: false,
nonEditableAliases: [ 'mygroup#mydomain.com.test-google-a.com' ] }"
When I use Try This API in the browswer, I do get the list of members, i.e. emails, role, etc.
For that you use the list from the members resource, not the groups.
exports.getGroupsMemberships = function (jwtClient) {
return new Promise((resolve, reject) => {
jwtClient.authorize(err => {
if (err) reject(err);
else resolve();
});
}).then(() => {
return new Promise((resolve, reject) => {
directory.members.list({
auth: jwtClient,
groupKey: "mygroup#mydomain.com",
},
function (err, resp) {
if (err) reject(err);
else resolve(resp);
});
});
});
};
If you want both the group metadata and the member list you'll need to make two calls:
exports.getGroupDataAndMembers = function (jwtClient) {
return new Promise((resolve, reject) => {
jwtClient.authorize(err => {
if (err) reject(err);
else resolve();
});
}).then(() => {
return new Promise((resolve, reject) => {
directory.groups.get({
auth: jwtClient,
domain: "mydomain.com",
groupKey: "mygroup#mydomain.com",
},
function (err, resp) {
if (err) reject(err);
else resolve(resp);
});
});
}).then((groupMetaCall) => {
return new Promise((resolve, reject) => {
directory.members.list({
auth: jwtClient,
groupKey: "mygroup#mydomain.com",
},
function (err, resp) {
if (err) reject(err);
else {
groupMetaCall.data.members = resp.data.members;
resolve(groupMetaCall);
}
});
});
});
};
The Try this API that you provided is for the get endpoint of the members resource. It returns the information about a member of a group.
Here is the documentation for the members.list:
https://developers.google.com/admin-sdk/directory/v1/reference/members/list

Express: how to end response

I new in Nodejs and faced some problems and need help
I broke down my app into modules and controllers
in app.js
app.use('/api/sync', syncDataRouter)
and in syncDataRouter.js
const routes = function (con, Reading, ReadingSummary) {
const syncDataRouter = express.Router();
const syncDataController = require('../controller/syncDataController')(con, Reading, ReadingSummary);
//Get All Readings from Database and push it to Mongo-db
syncDataRouter.route('/')
.get(syncDataController.sync);
return syncDataRouter;
};
module.exports = routes;
and in controller
const syncDataController = function (con, Reading, ReadingSummary) {
function getAllCompletedSessions() {
return new Promise((resolve, reject) => {
const sql = 'SELECT * FROM session WHERE endTime IS NOT NULL';
con.query(sql, (err, rows) => {
if (err) reject(new Error(err));
resolve(rows);
});
});
};
function getSessionPlayers(sessionId) {
return new Promise((resolve, reject) => {
const sql = 'SELECT * FROM sessionplayers WHERE sessionId = ?';
con.query(sql, [sessionId], (err, rows) => {
if (err) reject(new Error(err));
resolve(rows);
});
});
};
const sync = (req, res) => {
getAllCompletedSessions()
.then(sessions => {
})
.catch(err => {
res.status(500).send({ message: err.message });
});
//The Problem
res.json('Done');
};
return {
sync: sync
}
}
module.exports = syncDataController;
the problem is if any error happened enter a catch block and also continue until res.json('Done'); and sent a message can't set headers after they are sent how to handle a situation like that
Try making the sql queries async
const syncDataController = function (con, Reading, ReadingSummary) {
async function getAllCompletedSessions() {
return new Promise((resolve, reject) => {
const sql = 'SELECT * FROM session WHERE endTime IS NOT NULL';
await con.query(sql, (err, rows) => {
if (err) reject(new Error(err));
resolve(rows);
});
});
};
async function getSessionPlayers(sessionId) {
return new Promise((resolve, reject) => {
const sql = 'SELECT * FROM sessionplayers WHERE sessionId = ?';
await con.query(sql, [sessionId], (err, rows) => {
if (err) reject(new Error(err));
resolve(rows);
});
});
};
const sync = (req, res) => {
getAllCompletedSessions()
.then(sessions => {
})
.catch(err => {
res.status(500).send({ message: err.message });
});
//The Problem
res.json('Done');
};
return {
sync: sync
}
}
module.exports = syncDataController;

Resources