Automate Google Cloud Print from Drive Folder - javascript

To preface, I have Google Cloud Print working through apps script. I have OAuth2 setup, and I was able to setup a Cloud Print API that prints a single file in my Google Drive to a printer on my Cloud Print.
With that said, I'm looking for a way to automate my script so that when a document gets placed in a specific folder on my Google Drive, it will print automatically. I've searched around and was unable to find anything similar. Here's my starting point (which was found here from a very helpful tutorial):
function printGoogleDocument(docId, docTitle) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": myPrinterId,
"content": docId,
"title": docTitle,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
So when I fill in my docID and PrinterID, it works fine for a single document. But like I said, I'm trying to automate this based on new files in a Drive folder. Any suggestions?

Related

Convert a PDF file to Google Doc using Google Drive API v3

I have uploaded a pdf file successfully to drive using a node server. However, I can not find a way to convert it to the google doc format so that it can be downloaded later as a docx document.
here is my actual code:
const fileMetadata = {
'name': 'new file.pdf',
//'mimeType': 'application/vnd.google-apps.document'
// trying to create it as a google doc directly does
// not work either
};
const media = {
mimeType: 'application/pdf',
body: fs.createReadStream(pdf)
};
drive.files.create({
resource: fileMetadata,
media,
fields: 'id'
}, (err, createdFile) => {
if (err) {
console.error(err);
} else {
// ------- COPY AS GOOGLE DOC
drive.files.copy({
fileId: createdFile.data.id,
requestBody:{
mimeType:'application/vnd.google-apps.document'
}
}, (err, googleDocFiles) => {
if (err) {
console.log(err)
// GaxiosError: Bad Request
// error: [
// { domain: 'global', reason: 'badRequest', message: 'Bad Request' } ]
} else {
console.log(googleDocFiles)
}
})
}});
What i have tried
using the files.upload method with the same requestBody returns a 200 response, however the pdf is unchanged
I know is possible, I did it before, using the copy method however now it not working and I have no clue why *sigh
EDIT
The mimeType in the request body is responsible for the 400 error, that is very weird since I am following the steps in the documentation here:
Import to Google Docs types section
this section is explicit about importing a CSV, however in the box under that section says that I can convert a pdf to doc using the corresponding mime type
I re-installed the package and it work

Spotify api add track to playlist

I am using ReactJS and trying to make simple site using the Spotify api.
I am also using the js package spotify-web-api-js. I have succeeded to get the current song playing and able to show it in the browser.
getNowPlaying(){
spotifyApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response.item.name,
albumArt: response.item.album.images[0].url
}
});
})
}
//this is from the github link above
Constr.prototype.getMyCurrentPlaybackState = function(options, callback) {
var requestData = {
url: _baseUri + '/me/player'
};
return _checkParamsAndPerformRequest(requestData, options, callback);
};
But the problem I am facing is to add a track to my playlist. I have tried to use the function replaceTracksInPlaylist from spotify-web-api-js but I cant manage to get it to work, I always get the 403 Forbidden error.
addToPlayList(){
spotifyApi.addTracksToPlaylist(listID, listOfSongID, callback);
}
//this is from the github link above
Constr.prototype.replaceTracksInPlaylist = function(playlistId, uris, callback) {
var requestData = {
url: _baseUri + '/playlists/' + playlistId + '/tracks',
type: 'PUT',
postData: { uris: uris }
};
return _checkParamsAndPerformRequest(requestData, {}, callback);
};
The first example also requires authentication as a access token but why does it not work when adding to a playlist?
I have also changed the scopes to the correct ones that the api documentation says i should use, playlist-modify-public and playlist-modify-private
var scope = 'playlist-modify-public playlist-modify-private user-read-private user-read-email user-read-playback-state';
I can test the api call from the api documentation site and insert my oauth token, track and the playlist id there, and that works fine, I also get this back from the call. I cant think of anything else to try and need some help figuring out the next step.

Write Form Data from my Chrome Extension to Google Sheets

Updated with snippets and today's progress:
I am writing a Chrome Extension that is essentially a popup with a form, and I would like to write data entered into that form into Google Sheets. Currently, my extension consists of a manifest.json and a popup script, and a background script.
manifest.json (relevant pieces):
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [{ "js": ["content.js"], "matches": ["<all_urls>"] }],
"permissions": [
"tabs",
"storage",
"<all_urls>",
"identity",
"https://*.googleapis.com/*"
]
popup.js (note: this is an extension to track MS symptoms)
const app = {
symptoms: [],
init: function () {
//cache some element references
let formEl = document.getElementById("symptoms-form");
let fatigue = document.getElementById("fatigue");
let tingling = document.getElementById("tingling");
let weakness = document.getElementById("weakness");
let vision = document.getElementById("vision");
let dizzy = document.getElementById("dizzy");
let cognition = document.getElementById("cognition");
let depression = document.getElementById("depression");
let balance = document.getElementById("balance");
//upon submit, update symptoms obj and send to background
formEl.addEventListener("submit", ev => {
ev.preventDefault();
console.log('button click')
this.symptoms.push({fatigue: fatigue.value})
this.symptoms.push({tingling: tingling.value})
this.symptoms.push({weakness: weakness.value})
this.symptoms.push({vision: vision.value})
this.symptoms.push({dizzy: dizzy.value})
this.symptoms.push({cognition: cognition.value})
this.symptoms.push({depression: depression.value})
this.symptoms.push({balance: balance.value})
// chrome.runtime.sendMessage({fn: 'getSymptoms'}, function(response) {
// console.log('popup got response', response)
// })
chrome.runtime.sendMessage({fn: 'setSymptoms', symptoms: this.symptoms})
});
}
}
document.addEventListener('DOMContentLoaded', () => {
app.init();
})
background.js - note: my current workaround is to load the data into Firebase, which you will see below:
console.log("Background running");
const background = {
symptoms: [],
init: function() {
//listen for any messages and route them to functions
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.fn in background) {
background[request.fn](request, sender, sendResponse);
}
const jsonObj = {}
jsonObj['symptoms'] = request.symptoms
console.log("message received", jsonObj);
this.postSymptoms(jsonObj)
});
},
postSymptoms: function(msg) {
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://ms-mysymptoms-1541705437963.firebaseio.com/symptoms.json", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(msg);
}
};
background.init();
I have set up a new project in the Google Developers console, enabled the Google Sheets API, and set up my credentials and API token. I tested in the Google API explorer that the authentication is set up properly and I can, indeed, write a row to my sheet. This is great news!
I am blocked right now on how to do this (write the data), directly from my Chrome extension. So far, I have saved all my credentials, set up a config file, and wrote my append method in a separate file locally.
sheets.js:
const {authorize, google} = require('./config')
const fs = require('fs')
const spreadsheetId = '---removed for this post--'
const append = (range, values) => {
fs.readFile('client_secret.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
// Authorize a client with credentials, then call the Google Sheets API.
authorize(JSON.parse(content), (auth) => {
const sheets = google.sheets({
version: 'v4',
auth
});
const valueInputOption = 'USER_ENTERED';
const resource = {
values
};
sheets.spreadsheets.values.append({
spreadsheetId,
range,
valueInputOption,
resource
}, (err, result) => {
if (err) {
console.log(err);
} else {
console.log("Success!");
}
});
});
});
}
// module.exports = {
// append
// };
When I try to integrate this code into my popup script, however, I encounter an error because in order to reference that config data and that append method, I have to use require in my popup script. Since the popup script is running in the browser, I can't use require (without webpack, that is).
I'm sure I'm going about this all wrong, so I could use a push in the right direction as to how to authenticate and append to Sheets from the browser if my configuration and authentication are stored in local files on my computer.
Solutions I've considered:
1 - spin up a REST API, post the data from the form to that endpoint, and have it act as a proxy to the Google Sheets API - this is not ideal.
2 - use webpack so that I can use require in my popup file
What would be the recommended way to do this? How should I integrate authentication and working with the Google Sheet into this extension?
Writing to a spreadsheet with Google's API is a PUT not a POST.
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/update
I had success with this using chrome.identity.getAuthToken, then running a fetch with the following:
chrome.identity.getAuthToken({interactive: true}, function(token) {
var params = {
'values': [
['Row 1 Col A','Row 1 Col B'],
['Row 2 Col A','Row 2 Col B'],
]
};
let init = {
method: 'PUT',
async: true,
body: JSON.stringify(params),
headers: {
Authorization: 'Bearer ' + token,
Content-Type': 'application/json'
},
contentType: 'json',
};
fetch('https://sheets.googleapis.com/v4/spreadsheets/***YOUR SHEET ID****/values/****YOUR RANGE*****?valueInputOption=USER_ENTERED&key=***YOUR API KEY***', init)
.then((response) => response.json())
.then(function(data) {
//console.log(data);
//Returns spreadsheet ID, update tange, cols and rows
});
})
});
That's all in the background script, where I've put Row 1 Col A etc as the values, that'll be the first cell of your range.
Hope that helps.
Careful! If you want to append data, the ? query parameter comes after the :append.
fetch(`https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}:append?valueInputOption=${valueInputOption}`, init)

How can I send email notifications with Parse and Mandrill?

I am trying to use Mandrill to send an event-based email notification to the users of my web app. I am using Parse with Back4App.
In this tutorial (https://docs.back4app.com/docs/integrations/parse-server-mandrill/), the hosting providers suggest using the following method to call the Mandrill cloud code from an Android application:
public class Mandrill extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Parse.initialize(new Parse.Configuration.Builder(this)
.applicationId("your back4app app id”)
.clientKey(“your back4app client key ")
.server("https://parseapi.back4app.com/").build()
);
Map < String, String > params = new HashMap < > ();
params.put("text", "Sample mail body");
params.put("subject", "Test Parse Push");
params.put("fromEmail", "someone#example.com");
params.put("fromName", "Source User");
params.put("toEmail", "other#example.com");
params.put("toName", "Target user");
params.put("replyTo", "reply-to#example.com");
ParseCloud.callFunctionInBackground("sendMail", params, new FunctionCallback < Object > () {
#Override
public void done(Object response, ParseException exc) {
Log.e("cloud code example", "response: " + response);
}
});
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mandrill);
}
}
How can I implement this in JavaScript with the Parse JavaScript SDK?
This is what I've done so far but it won't send an email. I have Mandrill set up, as well as a verified email domain and valid DKIM and SPF.
// Run email Cloud code
Parse.Cloud.run("sendMail", {
text: "Email Test",
subject: "Email Test",
fromEmail: "no-reply#test.ca",
fromName: "TEST",
toEmail: "test#gmail.com",
toName: "test",
replyTo: "no-reply#test.ca"
}).then(function(result) {
// make sure to set the email sent flag on the object
console.log("result :" + JSON.stringify(result));
}, function(error) {
// error
});
I don't even get a result in the console, so I figure the cloud code is not even executing.
You have to add the Mandrill Email Adapter to the initialisation of your Parse Server, as described on their Github page. Also check the Parse Server Guide for how to initialise or use their example project.
Then set up Cloud Code by following the guide. You'll want to either call a Cloud Code function using your Android app or from any Javascript app, or use beforeSave or afterSave hooks of a Parse Object directly in Cloud Code, which allow you to send Welcome Emails when a user signs up. That could come in handy if you want to implement behaviour based emails based on object updates. Plus, because it is on the server and not the client, it is easier to maintain and scale.
To make the Cloud Code function actually send an email via Mandrill, you need to add some more code to your Cloud Code function. First, add a file with these contents:
var _apiUrl = 'mandrillapp.com/api/1.0';
var _apiKey = process.env.MANDRILL_API_KEY || '';
exports.initialize = function(apiKey) {
_apiKey = apiKey;
};
exports.sendTemplate = function(request, response) {
request.key = _apiKey;
return Parse.Cloud.httpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
url: 'https://' + _apiUrl + '/messages/send-template.json',
body: request,
success: function(httpResponse) {
if (response) {
response.success(httpResponse);
}
return Parse.Promise.resolve(httpResponse);
},
error: function(httpResponse) {
if (response) {
response.error(httpResponse);
}
return Parse.Promise.reject(httpResponse);
}
});
};
Require that file in your Cloud Code file, and use it like any other Promise.
var Mandrill = require("./file");
Mandrill.sendTemplate({
template_name: "TEMPLATE_NAME",
template_content: [{}],
key: process.env.MANDRILL_API_KEY,
message: {
global_merge_vars: [{
name: "REPLACABLE_CONTENT_NAME",
content: "YOUR_CONTENT",
}],
subject: "SUBJECT",
from_email: "YOUR#EMAIL.COM",
from_name: "YOUR NAME",
to: [{
email: "RECIPIENT#EMAIL.COM",
name: "RECIPIENT NAME"
}],
important: true
},
async: false
})
.then(
function success() {
})
.catch(
function error(error) {
});
Make sure you create a template on Mailchimp, right click it and choose "Send to Mandrill", so that you can use that template's name when sending via the API.
It's a bit involved, but once set up, it works like a charm. Good luck!

Chrome Apps : How to save blob content to fileSystem in the background?

In Chrome Apps, I'm downloading a blob content from a server using JavaScript XHR (Angular $http GET in particular, with response type 'blob')
How should I save this to chrome application's file system?
Currently using an Angular wrapper on HTML5 filesystem API
https://github.com/maciel310/angular-filesystem
I do not want to show user a popup (hence I can't use chrome.fileSystem. chooseEntry )
The chrome.fileSystem.requestFileSystem API is only supported by Kiosk-only apps.
Hence I'm using HTML5 FileSystem API instead of chrome's.
I'm using following code to make XHR to fetch blob.
$http({
url: SERVER_URL+"/someVideo.mp4",
method: "GET",
responseType: "blob"
}).then(function(response) {
console.log(response);
fileSystem.writeBlob(response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
}, function (response) {
});
This is my writeBlob method
writeBlob: function(fileName, blob, append) {
append = (typeof append == 'undefined' ? false : append);
var def = $q.defer();
fsDefer.promise.then(function(fs) {
fs.root.getFile(fileName, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
if(append) {
fileWriter.seek(fileWriter.length);
}
var truncated = false;
fileWriter.onwriteend = function(e) {
//truncate all data after current position
if (!truncated) {
truncated = true;
this.truncate(this.position);
return;
}
safeResolve(def, "");
};
fileWriter.onerror = function(e) {
safeReject(def, {text: 'Write failed', obj: e});
};
fileWriter.write(blob);
}, function(e) {
safeReject(def, {text: "Error creating file", obj: e});
});
}, function(e) {
safeReject(def, {text: "Error getting file", obj: e});
});
}, function(err) {
def.reject(err);
});
return def.promise;
},
This shows SECURITY_ERR as It was determined that certain files are unsafe for access within a Web application, or that too many calls are being made on file resources.
What's the solution for this?
I've tried using --allow-file-access-from-files flag while launching app. It doesn't help.
Chrome Application's sandbox storage doesn't allow files to be stored in root directory (i.e. / )
Modify the code to save it in a specific sub-directory under it.
For example -
fileSystem.writeBlob("/new"+response.name, response).then(function() {
console.log("file saved");
}, function(err) {
console.log(err);
});
This would successfully save the file under /new/ directory.
To expand on this, here is a full example app on how to download a file and save the blob and display it back to the user.
https://github.com/PierBover/chrome-os-app-download-example

Categories

Resources