Google Drive API - Automated Queries Message - docker

I am using this Ghost plugin to store image data on Google Drive. Recently, images have stopped loading with this error page downloaded in place of the image:
The site is running in a containerized Ghost instance on Google Cloud Run, source here
Do I need to open a support ticket somewhere to resolve this? Site in question is here
EDIT: Here is the code used to access the saved content.
jwtClient.authorize(function(err, tokens) {
if (err) {
return next(err);
}
const drive = google.drive({
version: API_VERSION,
auth: jwtClient
});
drive.files.get(
{
fileId: id
},
function(err, response) {
if (!err) {
const file = response.data;
const newReq = https
.request(
file.downloadUrl + "&access_token=" + tokens.access_token,
function(newRes) {
// Modify google headers here to cache!
const headers = newRes.headers;
headers["content-disposition"] =
"attachment; filename=" + file.originalFilename;
headers["cache-control"] = "public, max-age=1209600";
delete headers["expires"];
res.writeHead(newRes.statusCode, headers);
// pipe the file
newRes.pipe(res);
}
)
.on("error", function(err) {
console.log(err);
res.statusCode = 500;
res.end();
});
req.pipe(newReq);
} else {
next(err);
}
}
);
});

Your problem is related to file.downloadUrl. This field is not guaranteed to work and is not supposed to be used to download files.
The correct way to do this is to use the webContentLink property instead. You can look at here for reference.

Related

Is there any way to track an event using firebase in electron + react

I want to ask about how to send an event using firebase & electron.js. A friend of mine has a problem when using firebase analytics and electron that it seems the electron doesn't send any event to the debugger console. When I see the network it seems the function doesn't send anything but the text successfully go in console. can someone help me to figure it? any workaround way will do, since he said he try to implement the solution in this topic
firebase-analytics-log-event-not-working-in-production-build-of-electron
electron-google-analytics
this is the error I got when Try to use A solution in Point 2
For information, my friend used this for the boiler plate electron-react-boilerplate
The solution above still failed. Can someone help me to solve this?
EDIT 1:
As you can see in the image above, the first image is my friend's code when you run it, it will give a very basic example like in the image 2 with a button to send an event.
ah just for information He used this firebase package :
https://www.npmjs.com/package/firebase
You can intercept HTTP protocol and handle your static content though the provided methods, it would allow you to use http:// protocol for the content URLs. What should make Firebase Analytics work as provided in the first question.
References
Protocol interception documentation.
Example
This is an example of how you can serve local app as loaded by HTTP protocol and simulate regular browser work to use http protocol with bundled web application. This will allow you to add Firebase Analytics. It supports poorly HTTP data upload, but you can do it on your own depending on the goals.
index.js
const {app, BrowserWindow, protocol} = require('electron')
const http = require('http')
const {createReadStream, promises: fs} = require('fs')
const path = require('path')
const {PassThrough} = require('stream')
const mime = require('mime')
const MY_HOST = 'somehostname.example'
app.whenReady()
.then(async () => {
await protocol.interceptStreamProtocol('http', (request, callback) => {
const url = new URL(request.url)
const {hostname} = url
const isLocal = hostname === MY_HOST
if (isLocal) {
serveLocalSite({...request, url}, callback)
}
else {
serveRegularSite({...request, url}, callback)
}
})
const win = new BrowserWindow()
win.loadURL(`http://${MY_HOST}/index.html`)
})
.catch((error) => {
console.error(error)
app.exit(1)
})
async function serveLocalSite(request, callback) {
try {
const {pathname} = request.url
const filepath = path.join(__dirname, path.resolve('/', pathname))
const stat = await fs.stat(filepath)
if (stat.isFile() !== true) {
throw new Error('Not a file')
}
callback(
createResponse(
200,
{
'content-type': mime.getType(path.extname(pathname)),
'content-length': stat.size,
},
createReadStream(filepath)
)
)
}
catch (err) {
callback(
errorResponse(err)
)
}
}
function serveRegularSite(request, callback) {
try {
console.log(request)
const req = http.request({
url: request.url,
host: request.url.host,
port: request.url.port,
method: request.method,
headers: request.headers,
})
if (req.uploadData) {
req.write(request.uploadData.bytes)
}
req.on('error', (error) => {
callback(
errorResponse(error)
)
})
req.on('response', (res) => {
console.log(res.statusCode, res.headers)
callback(
createResponse(
res.statusCode,
res.headers,
res,
)
)
})
req.end()
}
catch (err) {
callback(
errorResponse(err)
)
}
}
function toStream(body) {
const stream = new PassThrough()
stream.write(body)
stream.end()
return stream
}
function errorResponse(error) {
return createResponse(
500,
{
'content-type': 'text/plain;charset=utf8',
},
error.stack
)
}
function createResponse(statusCode, headers, body) {
if ('content-length' in headers === false) {
headers['content-length'] = Buffer.byteLength(body)
}
return {
statusCode,
headers,
data: typeof body === 'object' ? body : toStream(body),
}
}
MY_HOST is any non-existent host (like something.example) or host that is controlled by admin (in my case it could be electron-app.rumk.in). This host will serve as replacement for localhost.
index.html
<html>
<body>
Hello
</body>
</html>

Is there a way to upload media to the Twitter API using the URL of the media resource?

I've created an app that allows users to upload their images to a Google Cloud Storage bucket - which is then used in social media sharing previews.
The image is uploaded directly to the bucket from the user's browser - using the Firebase API.
What I also want to do is - when an image is saved - to automatically post that image on my app's twitter feed.
The way I've done this is to use a Cloud Function trigger on Cloud Storage - which downloads the image and then uploads via the Twitter API.
There's essentially an unnecessary double handling of traffic here is there a way to just give the Twitter API the public location of the file and have it source the file directly?
Here's my code for the current solution:
class Defferred {
constructor() {
const that = this;
this.prom = new Promise((resolve, reject) => {
that.resolve = resolve;
that.reject = reject;
});
}
}
exports.onNewImage = functions.storage.object().onFinalize((object) => {
const prom = new Defferred();
bucket.file(object.name).download((err, file, response) => {
if (err) {
return prom.reject(err);
} else {
twitterClient.post('media/upload', {
media: file
}, (err, media, response) => {
if (!err) {
let status = {
status: "Somebody created this at https://geoplanets.io #geometry #geometricart",
media_ids: media.media_id_string
}
twitterClient.post('statuses/update', status, (error, tweet, response) => {
if (!error) {
return prom.resolve(response);
} else {
return prom.reject(error);
}
});
} else {
return prom.reject(err);;
}
});
}
});
return prom.prom;
});
Is there an alternative way of doing this that doesn't involve downloading the file? - A good answer would highlight the relevant parts of the API documentation that highlight how I would go about working this out myself.
The Twitter node api doesn't have a way to simply pass an URL for media upload. The example they give shows what you're doing now - sending the full content with the request.
The node client is just a wrapper around the REST API, and if you read its docs, you'll see that you have to provide the file content directly to the POST.
Yes!
We can upload media using URL of file by making the downstream of a file.
First we need to make Axios request to have a buffer of it then we can pass it with file type using
twitter-api-v2
use it in this package or REST API
const client = new TwitterApi({
appKey: CONSUMER_KEY,
appSecret: CONSUMER_SECRET,
accessToken: oauth_token,
accessSecret: oauth_token_secret,
});
const url = 'URL OF THE FILE';
const downStream = await axios({
method: 'GET',
responseType: 'arraybuffer',
url: url,
}).catch(function (error) {
res.send({error:error});
});
const mediaId = await client.v1.uploadMedia(downStream.data,{ mimeType: 'png'});
const newTweet = await client.v1.tweet('Hello link tweet!', { media_ids: mediaId });
sample Image

How to upload multipart image from ios to server using node.js (socket script)

I need to upload image from my ios application to server using node socket script.Below is my script that i have tried.I could not identify the issue.Please help me if any thing wrong or missing in script side or ios side.
socket.on('Upload_Image', function(data)
{
var multer = require('multer')
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage }).single(data.file);
console.log(data.file);
app.post('/', function (req, res)
{
upload(req,res,function(req,res)
{
if(err)
{
console.log("error uploading file");
}
else
{
console.log("uploaded");
}
});
});
});
Above code - > data is the dictionary that i am passing from ios and data.file is the parameter name.
uploads -> is a folder where i need to upload image
==> ios code to call socket event
let msgDictionary = [
"file":UIImagePNGRepresentation(imageData)!];
APP_DELEGATE.socketIOHandler?.socket?.emit("Upload_Image",msgDictionary)
Alternate suggestions are also welcome.

How to Update Device Configuration using Google Cloud functions and MQTT bridge

I am using the Google Cloud IoT with Pub/Sub.
I have a device reading sensor data and sending it to a topic in Pub/Sub.
I have a topic cloud function that is triggered by this message and I would like to have the device configuration updated, however I am unable to do so due to the following permission error.
index.js :
/**
* Triggered from a message on a Cloud Pub/Sub topic.
*
* #param {!Object} event The Cloud Functions event.
* #param {!Function} The callback function.
*/
var google = require('googleapis');
//var tt = google.urlshortener('v1');
//console.log(Object.getOwnPropertyNames(google.getAPIs()));
var cloudiot = google.cloudiot('v1');
function handleDeviceGet(authClient, name, device_id, err, data) {
if (err) {
console.log('Error with get device:', device_id);
console.log(err);
return;
}
console.log('Got device:', device_id);
console.log(data);
console.log(data.config);
var data2 = JSON.parse(
Buffer.from(data.config.binaryData, 'base64').toString());
console.log(data2);
data2.on = !data2.on;
console.log(data2);
var request2 = {
name: name,
resource: {
'versionToUpdate' : data.config.version,
'binaryData' : Buffer(JSON.stringify(data2)).toString('base64')
},
auth: authClient
};
console.log('request2' + request2);
var devices = cloudiot.projects.locations.registries.devices;
devices.modifyCloudToDeviceConfig(request2, (err, data) => {
if (err) {
console.log('Error patching device:', device_id);
console.log(err);
} else {
console.log('Patched device:', device_id);
console.log(data);
}
});
}
const handleAuth = (device_id) => {
console.log(device_id);
return (err, authClient) => {
const project_id = 'animated-bonsai-195009';
const cloud_region = 'us-central1';
const registry_id = 'reg1';
const name = `projects / ${project_id} /locations / ${cloud_region} /` +
`registries / ${registry_id} /devices / ${device_id}`;
if (err) {
console.log(err);
}
if (authClient.createScopedRequired &&
authClient.createScopedRequired()) {
authClient = authClient.createScoped(
['https://www.googleapis.com/auth/cloud-platforme']);
}
var request = {
name: name,
auth: authClient
};
// Get device version
var devices = cloudiot.projects.locations.registries.devices;
devices.get(request, (err, data) =>
handleDeviceGet(authClient, name, device_id, err, data));
}
};
exports.subscribe = (event, callback) => {
// The Cloud Pub/Sub Message object.
const pubsubMessage = event.data;
// We're just going to log the message to prove that
// it worked.
var obj = JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString());
console.log(Buffer.from(pubsubMessage.data, 'base64').toString());
console.log(event);
console.log(Object.getOwnPropertyNames(event));
console.log(callback);
let message = {
"watter": 1
};
message = new Buffer(JSON.stringify(message));
const req = {
name: event.data.deviceId,
resource: message
};
console.log(obj.deviceId);
google.auth.getApplicationDefault(handleAuth(obj['deviceId']));
// Don't forget to call the callback.
callback();
};
package.json :
{
"name": "sample-pubsub",
"version": "0.0.1",
"dependencies": {
"googleapis": "25.0.0"
}
}
Error:
A few options:
Check that you have enabled API access for the Google Cloud IoT Core API for the project used when creating the Google Cloud Function.
Check that you have enabled billing for your project
If you are deploying your Google Cloud Functions with gcloud beta functions deploy ... from the folder with your .js and package.json files, you may want to set the environment variables (GCLOUD_PROJECT and GOOGLE_APPLICATION_CREDENTIALS) or use gcloud auth application-default login before deploying in case you have multiple Google Cloud projects and need to enable the API on the configured one.
Update This community tutorial shows you how to do this - note that there have been some updates to Google Cloud Functions that require you to use a newer version of the Node JS client library as is done in the NodeJS sample and as corrected in this PR, note the version of the client library in package.json.

Ajax In Firefox Plugin

Is there any way to send Ajax requests to server from a Firefox plugin? If yes, how? If no, how do we have client server communication in Firefox plugins?
I want to get some JSON data from server and manipulate the DOM object according to the client input.
I am pretty a beginner in plugin programming.
You can send ajax requests from firefox extension using xmlHTTPRequest, like in any other web application.
From a contentscript you should add the permissions to access cross-domain content, URLs you want to:
"permissions": {
"cross-domain-content": ["http://example.org/", "http://example.com/"]
}
More info in the documentation.
Here's a simple snippet that does XHR request, WITHOUT cookies (due to flag Ci.nsIRequest.LOAD_ANONYMOUS can remove to send with cookies) (MDN :: Info on flags]. Copy this first code block in, then see usage examples below.
var {Cu: utils, Cc: classes, Ci: instances} = Components;
Cu.import('resource://gre/modules/Services.jsm');
function xhrGetPost(url, post_data, cb) {
let xhr = Cc["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
let handler = ev => {
evf(m => xhr.removeEventListener(m, handler, !1));
switch (ev.type) {
case 'load':
if (xhr.status == 200) {
cb(xhr.response);
break;
}
default:
Services.prompt.alert(null, 'XHR Error', 'Error Fetching Package: ' + xhr.statusText + ' [' + ev.type + ':' + xhr.status + ']');
break;
}
};
let evf = f => ['load', 'error', 'abort'].forEach(f);
evf(m => xhr.addEventListener(m, handler, false));
xhr.mozBackgroundRequest = true;
if (post_data == undefined) {
post_data = null;
}
if (post_data) {
xhr.open('POST', url, true);
} else {
xhr.open('GET', url, true);
}
xhr.channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS | Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_PERSISTENT_CACHING;
//xhr.responseType = "arraybuffer"; //dont set it, so it returns string, you dont want arraybuffer. you only want this if your url is to a zip file or some file you want to download and make a nsIArrayBufferInputStream out of it or something
xhr.send(post_data);
}
Example usage of for POST:
var href = 'http://www.bing.com/'
xhrGetPost(href, 'post_data1=blah&post_data2=blah_blah', data => {
Services.prompt.alert(null, 'XHR Success', data);
});
Example usage of for GET:
var href = 'http://www.bing.com/'
xhrGetPost(href, null, data => {
Services.prompt.alert(null, 'XHR Success', data);
});

Resources