Script for sending email attachments from google script - attachment

Here is the script for the button i am working on. the script creates the pdf and folder, Sends email but doesn't grab the attachment.
I have removed the file id and url ect.
The main section i am having problems is the attachment.
Really appreciate any help with this one.
function getpdf2(){
SpreadsheetApp.flush();
//make pdf
var theurl = ''
+ '' //the file ID
+ '/export?exportFormat=pdf&format=pdf'
+ '&size=LETTER'
+ '&portrait=true'
+ '&fitw=true'
+ '&top_margin=0.50'
+ '&bottom_margin=0.50'
+ '&left_margin=0.50'
+ '&right_margin=0.50'
+ '&sheetnames=false&printtitle=false'
+ '&pagenum=false'
+ '&gridlines=false'
+ '&fzr=FALSE'
+ '&gid='
+ ''; //the sheet's Id
var token = ScriptApp.getOAuthToken();
var docurl = UrlFetchApp.fetch(theurl, { headers: { 'Authorization': 'Bearer ' + token }
});
var fileid = DriveApp.createFile(docurl.getBlob()).setName('Quote mike.pdf').getId();
//var blob = spreadsheetFile.getAs('application/pdf');
var pdf = docurl.getBlob().setName('Quote mike.pdf');
var pdf = docurl.getBlob().getAs('application/pdf').setName('Quote mike.pdf');
var filetodel = DriveApp.getFileById(fileid);
DriveApp.getRootFolder().createFolder("mike"); //comment if folder exists
// if folder exists use next
if (DriveApp.getFoldersByName("mike").hasNext()){
var folder = DriveApp.getFoldersByName("mike").next();
filetodel.makeCopy(folder);
var address = Browser.inputBox('Enter Email Address', Browser.Buttons.OK_CANCEL);
//function sendEmailWithAttachments(){
//var fileid = SpreadsheetApp.getActiveSpreadsheet()
//getAs(MimeType.PDF);
MailApp.sendEmail({to:address,
subject: "QUOTE",
body:"Thank You!!",
attachments: [fileid[0].getAs(MimeType.pdf)]
})
DriveApp.removeFile(filetodel);
}
}

Related

Copy/rename google sheet, share & get share id with script in form

Is it possible for a script to copy/rename an (unrelated) Google spreadsheet, share it with a given email (preferably testing for the existence of a google account associated with the given email first), and save the shared url? I have spent hours and can't find any part of the answer to this: nothing on copying/renaming, nothing on share id. I may be missing some keyword or something. I realize I'll probably be downvoted for a general question, but this is the only Google Script support out there, I think. If you give me a thread, I'll follow it.
So: I had to figure this out, and finally hired someone to code this snippet for me, here's what I got. This works pretty great for me. I did a tiny bit of customization.
Here's the requirement:
Given 2 Google Sheets, GTemplate & GTracker (these are two separate spreadsheets, not tabs in the same spreadsheet). Create a form (that reports to a tab/sheet in GTracker) which a user (anyone) fills in online with an email "UserEmail", and a string "UserID". Upon submission:
1) Make a copy of GTemplate, and rename it to "GTUserID" (if GTUserID already exists, name it GTUserID1, 2, or whatever)
2) Check that the submitted email has an associated Google Account
3) Share GTUserID with UserEmail
4) Save the URL of GTUserID to GTracker
5) Send an email to UserEmail confirming success or failure of above
//************ Edit here *******************************
var stremplateID = '1PBO9KhoZa9iX3Uik-FxXGnvhgs0BoNQUJmV95UUg56o';
//******************************************************
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Initialization')
.addItem('Initialize', 'setTrigger')
.addToUi();
}
function setTrigger(){
var arr= ScriptApp.getProjectTriggers();
for (var i= arr.length; i>0; i--){
ScriptApp.deleteTrigger(arr[i-1])
}
ScriptApp.newTrigger('onFormSubmit')
.forSpreadsheet(SpreadsheetApp
.getActiveSpreadsheet().getId())
.onFormSubmit()
.create()
}
function onFormSubmit(e) {
try {
//Logger.log(JSON.stringify(e))
var folder;
var strEmail = e.namedValues.Email;
var strUID = e.namedValues['User ID'];
//Logger.log(strEmail)
//Logger.log(strUID)
var oldFile = DriveApp.getFileById(stremplateID);
var folders = oldFile.getParents();
while (folders.hasNext()) {
folder = folders.next();
break;
}
if ((typeof folder) != "object") {
folder = DriveApp.getRootFolder();
}
var bolFlag = false;
var bolFlag1 = false;
var i = 0;
var myRegexp = new RegExp('[^a-zA-Z0-9.-]','g');
var strProcUID=String(strUID).replace(myRegexp, "_");
//Logger.log(strProcUID)
var strFilename = strProcUID;
while (!bolFlag) {
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
if (file.getName() == strFilename) {
bolFlag1 = true;
}
}
if (!bolFlag1) {
bolFlag = true;
} else {
i = i + 1;
strFilename = strProcUID + i;
bolFlag1 = false;
}
}
var newFile = oldFile.makeCopy(strFilename, folder);
newFile.addEditors(strEmail);
var link = newFile.getUrl();
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var row = sh.getLastRow();
var col = sh.getLastColumn();
sh.getRange(row, col, 1, 1).setValue(link);
var body = 'Dear ' + strUID + ',\n' +
'Your request has been processed successfully.\n' +
'The file can be seen here:\n' +
link + '\n' +
'Regards,\n ' +
'Admin';
GmailApp.sendEmail(strEmail, 'Request Processed', body);
} catch (e) {
var body = '\n' +
'An error occurred while processing the request:\n' +
'User ID: ' + strUID + '\n ' +
'Email: ' + strEmail + '\n ' +
'Error: ' + e;
GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), 'Error processing a request', body);
var body = 'Dear ' + strUID + ',\n' +
'Sorry, an error occurred while processing your request.\n' +
'Regards,\n ' +
'Admin';
GmailApp.sendEmail(strEmail, 'Error processing the request', body);
}
}
Perhaps this will be helpful to someone else. The things it does that I couldn't find was copying a copied/shared Google Sheet URL into a different sheet (for creating daughter shared documents for different projects, initiated by the project teams, still owned by the admin account, with internal fields readily accessible since we've got the URL). I hope that's clear and helpful.

youtube data api retrieve view counts

i implemented in my .net project api youtube.
this is my code
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = "MY_API_KEY",
ApplicationName = "MY_APPLICATION_NAME"
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = SearchText;
searchListRequest.MaxResults = 50;
searchListRequest.Order = SearchResource.ListRequest.OrderEnum.ViewCount;
var searchListResponse = await searchListRequest.ExecuteAsync();
foreach (var searchResult in searchListResponse.Items)
{
if (searchResult.Id.Kind == "youtube#video")
{
}
}
in searchResult not have a STATISTICS (for example view counts).
How to?
Because search.list don't have the part statitics you need to call two time the API.
One time with the request search.list
You get the id of the channel
And a second call with channel.list, with the id of the channel and parameter: statistics
Then you have viewCount
Doc can help : https://developers.google.com/youtube/v3/docs/search/list
https://developers.google.com/youtube/v3/docs/channels/list
I came across the same problem using their Javascript based API search functionality.
Looks like they do not have a build in "views" option for their search based API.
https://developers.google.com/youtube/v3/docs/search#snippet
How ever, you can use their JSON based API and create a AJAX based search box, which returns a JSON based response with a option for view count!
https://developers.google.com/youtube/2.0/developers_guide_jsonc
Created this myself, check it out:
$(document).ready(function() {
var q = $('#query');
$('#search-button').click(function(e) {
var url = "https://gdata.youtube.com/feeds/api/videos?q=" + q.val() + "&v=2&alt=jsonc";
$.getJSON( url, function( response ) {
for(var i = 0; i < response.data.items.length; i++) {
var tr = "<tr>",
title = "<td>" + response.data.items[i].title + "</td>",
views = "<td>" + response.data.items[i].viewCount + "</td>",
likes = "<td>" + response.data.items[i].likeCount + "</td>",
dislikes = "<td>" + (response.data.items[i].ratingCount - response.data.items[i].likeCount) + "</td>",
endtr = "</tr>";
$('#search-container').append(tr + title + views + likes + dislikes + endtr);
}
});
e.preventDefault();
});
});
http://jsfiddle.net/19m9tLo3/1/

Streaming mp4 videos from serversocket on AIR

I am trying to build a mini-webserver on an iPad inside an Adobe AIR application.
I am using the ServerSocket class to set up the webserver as shown by example at http://coenraets.org/blog/2010/07/creating-a-web-server-using-the-new-server-socket-api-in-air-2/.
I am trying to extend this by allowing the webserver to serve mp4 video files.
I have added the mimetype: mimeTypes[".mp4"] = "video/mp4";
but serving an mp4 to be played in a browser is not exactly the same as providing a html file.
Anyone can point me in the right direction for this? This is the code I currently have when the socket is responding:
private function webserverConnectionSocketDataHandler(evt:ProgressEvent):void{
try
{
var socket:Socket = evt.target as Socket;
var bytes:ByteArray = new ByteArray();
socket.readBytes(bytes);
var request:String = "" + bytes;
var filePath:String = request.substring(5, request.indexOf("HTTP/") - 1);
var file:File = File.applicationDirectory.resolvePath("AppStorage").resolvePath(filePath);
if (file.exists && !file.isDirectory)
{
//Range: bytes=0-131726
var offset:uint = 0;
var bytesRequested:uint = 0;
if(request.indexOf("Range: bytes=") >= 0){
offset = uint(request.split("Range: bytes=")[1].split("-")[0]);
bytesRequested = (request.split("Range: bytes=")[1].split("-")[1]);
}
if(bytesRequested == 0) bytesRequested = file.size;
var stream:FileStream = new FileStream();
stream.open( file, FileMode.READ );
var content:ByteArray = new ByteArray();
stream.readBytes(content, offset, bytesRequested);
stream.close();
if(bytesRequested != file.size){
socket.writeUTFBytes("HTTP/1.1 206 Partial Content\n");
socket.writeUTFBytes("Content-Type: " + getMimeType(filePath) + "\n\n");
socket.writeUTFBytes("Content-Range: " + offset + "-" + bytesRequested + "/" + file.size + "\n\n");
socket.writeUTFBytes("Content-Length: " + (bytesRequested-offset) + "\n\n");
socket.writeUTFBytes("Date: " + new Date().toLocaleTimeString() + "\n\n");
}else{
socket.writeUTFBytes("HTTP/1.1 200 OK\n");
socket.writeUTFBytes("Content-Type: " + getMimeType(filePath) + "\n\n");
socket.writeUTFBytes("Content-Length: " + file.size + "\n\n");
}
socket.writeBytes(content);
}
else
{
socket.writeUTFBytes("HTTP/1.1 404 Not Found\n");
socket.writeUTFBytes("Content-Type: text/html\n\n");
socket.writeUTFBytes("<html><body><h2>Page Not Found</h2></body></html>");
}
socket.flush();
socket.close();
}
catch (error:Error)
{
trace(error.message, "Error");
}
}
But that is not really working as expected. The goal is to be able to view an mp4 from inside my iPad application's AppStorage directory from inside my browser on PC. It works for html files, not for mp4.

firefox extension working on page load

I'm trying to create my first extension.
I've found this sample: http://blog.mozilla.org/addons/2009/01/28/how-to-develop-a-firefox-extension/
I need to get some html content on a specific page and write something in the same page, so I modified it and got what I needed (with javascript I added content in the table I want). But to view my content I have to launch the extension from the button on the status bar, while I would like to have it already active in the page as I load/reload it (with a check on the url so to have it working only on that page) but I can't have it automatically.
I tried to add linkTargetFinder.run(); on init area, but... nothing. Moreover the extension as an "autorun" but eve if active, I don0t see any change.
any working sample?
Thanks
Nadia
Here it is the code (I edited just the .js file), I commented a couple of test not working...
var linkTargetFinder = function () {
var prefManager = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
return {
init : function () {
gBrowser.addEventListener("load", function () {
var autoRun = prefManager.getBoolPref("extensions.linktargetfinder.autorun");
if (autoRun) {
linkTargetFinder.run();
}
//linkTargetFinder.run(); // doesn't work
}, false);
//linkTargetFinder.run(); // doesn't work
alert("ZZZZZZZZZZZZZZZZZZ"); // doesn't work
},
run : function () {
var head = content.document.getElementsByTagName("head")[0],
style = content.document.getElementById("link-target-finder-style"),
allLinks = content.document.getElementsByTagName("a"),
foundLinks = 0;
if (!style) {
style = content.document.createElement("link");
style.id = "link-target-finder-style";
style.type = "text/css";
style.rel = "stylesheet";
style.href = "chrome://linktargetfinder/skin/skin.css";
head.appendChild(style);
}
for (var i=0, il=allLinks.length; i<il; i++) {
elm = allLinks[i];
if (elm.getAttribute("target")) {
elm.className += ((elm.className.length > 0)? " " : "") + "link-target-finder-selected";
foundLinks++;
}
}
if (foundLinks === 0) {
alert("No links found with a target attribute");
}
else {
//alert("Found " + foundLinks + " links with a target attribute");
}
t = content.document.getElementById("ERSContainer"), // ID of the table
d = t.getElementsByTagName("tr")[1],
r = d.getElementsByTagName("td")[1];
var myMail = "mail: "+r.textContent; //ok scrive nella td
var myName = content.document.getElementById("buyercontactname").value;
var myAddr1 = content.document.getElementById("buyeraddress1").value;
var myAddr2 = content.document.getElementById("buyeraddress2").value;
var myCity = content.document.getElementById("buyercity").value;
var myProv = content.document.getElementById("buyerstateprovince").value;
var myCAP = content.document.getElementById("buyerzip").value;
var elt = content.document.getElementById("buyercountry");
var myCountry = elt.options[elt.selectedIndex].text;
var myTel = content.document.getElementById("dayphone1").value;
var myTag1 = "<tr><td colspan='2'>OK!!!<br />";
var myTag2 = "</td></tr>";
z= t.innerHTML;
t.innerHTML = myTag1 + myMail +
" - "+myName+
myAddr1 + "<br />" +
myAddr2 + "<br />" +
myCity + "<br />" +
myProv + "<br />" +
myCAP + "<br />" +
myCountry + "<br />" +
myTel + "<br />" +
myFlash+
myTag2+z;
}
};
}();
window.addEventListener("load", linkTargetFinder.init, false);
If what you are doing is running a bit of JavaScript on a specific web page, like adding content into a table, maybe you should consider doing a userscript for the Greasemonkey addon instead of a full addon. With this you write your JS for the page and it gets executed each time you browse this specific page.
edit:
Try with this :
init: function () {
gBrowser.addEventListener("load", linkTargetFinder.run, true);
},
...
I bet that the extensions.linktargetfinder.autorun does not exist. So getBoolPref throws an exception and the rest is history.
Change your code to the following
var autoRun;
try {
autoRun = prefManager.getBoolPref("extensions.linktargetfinder.autorun");
} catch(e){
autoRun = false;
}

"Authorization is required to perform that action" in Google Scripts with no way to give authorization

I am trying to create a sort of middleware so some legacy software I am working on can consume Twitter feeds.
Since Twitter has made API 1.0 obsolete and 1.1 requires OAuth and because for this project I only have client-side scripting available to me, I opted to use a Google script to perform the OAuth negotiation:
Source: http://www.labnol.org/internet/twitter-rss-feeds/27931/
function start() {
// Get your Twitter keys from dev.twitter.com
var CONSUMER_KEY = "-----";
var CONSUMER_SECRET = "----";
// Ignore everything after this line
initialize(CONSUMER_KEY, CONSUMER_SECRET);
}
function initialize(key, secret) {
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", key);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", secret);
var url = ScriptApp.getService().getUrl();
if (url) {
connectTwitter();
var msg = "";
msg += "Sample RSS Feeds for Twitter\n";
msg += "============================";
msg += "\n\nTwitter Timeline of user #labnol";
msg += "\n" + url + "?action=timeline&q=labnol";
msg += "\n\nTwitter Favorites of user #labnol";
msg += "\n" + url + "?action=favorites&q=labnol";
msg += "\n\nTwitter List labnol/friends-in-india";
msg += "\n" + url + "?action=list&q=labnol/friends-in-india";
msg += "\n\nTwitter Search for New York";
msg += "\n" + url + "?action=search&q=new+york";
msg += "\n\nYou should replace the value of 'q' parameter in the URLs as per requirement.";
msg += "\n\nFor help, please refer to http://www.labnol.org/?p=27931";
MailApp.sendEmail(Session.getActiveUser().getEmail(), "Twitter RSS Feeds", msg);
}
}
function doGet(e) {
var a = e.parameter.action;
var q = e.parameter.q;
var feed;
switch (a) {
case "timeline":
feed = "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=" + q;
break;
case "search":
feed = "https://api.twitter.com/1.1/search/tweets.json?q=" + encodeString(q);
break;
case "favorites":
feed = "https://api.twitter.com/1.1/favorites/list.json?screen_name=" + q;
break;
case "list":
var i = q.split("/");
feed = "https://api.twitter.com/1.1/lists/statuses.json?slug=" + i[1] + "&owner_screen_name=" + i[0];
break;
default:
feed = "https://api.twitter.com/1.1/statuses/user_timeline.json";
break;
}
var id = Utilities.base64Encode(feed);
var cache = CacheService.getPublicCache();
var rss = cache.get(id);
if ((!rss) || (rss == "undefined")) {
rss = JSONtoRSS(feed, a, q);
cache.put(id, rss, 3600);
}
return ContentService.createTextOutput(rss)
.setMimeType(ContentService.MimeType.RSS);
}
function JSONtoRSS(json, type, key) {
oAuth();
var options = {
"method": "get",
"oAuthServiceName": "twitter",
"oAuthUseToken": "always"
};
try {
var result = UrlFetchApp.fetch(json, options);
if (result.getResponseCode() === 200) {
var tweets = Utilities.jsonParse(result.getContentText());
if (type == "search")
tweets = tweets.statuses;
if (tweets) {
var len = tweets.length;
var rss = "";
if (len) {
rss = '<?xml version="1.0"?><rss version="2.0">';
rss += ' <channel><title>Twitter ' + type + ': ' + key + '</title>';
rss += ' <link>' + htmlentities(json) + '</link>';
rss += ' <pubDate>' + new Date() + '</pubDate>';
for (var i = 0; i < len; i++) {
var sender = tweets[i].user.screen_name;
var tweet = htmlentities(tweets[i].text);
rss += "<item><title>" + sender + ": " + tweet + "</title>";
rss += " <author>" + tweets[i].user.name + " (#" + sender + ")</author>";
rss += " <pubDate>" + tweets[i].created_at + "</pubDate>";
rss += " <guid isPermaLink='false'>" + tweets[i].id_str + "</guid>";
rss += " <link>https://twitter.com/" + sender + "/statuses/" + tweets[i].id_str + "</link>";
rss += " <description>" + tweet + "</description>";
rss += "</item>";
}
rss += "</channel></rss>";
return rss;
}
}
}
} catch (e) {
Logger.log(e.toString());
}
}
function connectTwitter() {
oAuth();
var search = "https://api.twitter.com/1.1/application/rate_limit_status.json";
var options = {
"method": "get",
"oAuthServiceName": "twitter",
"oAuthUseToken": "always"
};
try {
var result = UrlFetchApp.fetch(search, options);
} catch (e) {
Logger.log(e.toString());
}
}
function encodeString(q) {
var str = encodeURIComponent(q);
str = str.replace(/!/g, '%21');
str = str.replace(/\*/g, '%2A');
str = str.replace(/\(/g, '%28');
str = str.replace(/\)/g, '%29');
str = str.replace(/'/g, '%27');
return str;
}
function htmlentities(str) {
str = str.replace(/&/g, "&");
str = str.replace(/>/g, ">");
str = str.replace(/</g, "<");
str = str.replace(/"/g, """);
str = str.replace(/'/g, "'");
return str;
}
function oAuth() {
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
}
I have followed all of the instructions prescribed in the guide including running 'start' twice... and all that does is send my email account an email with the various URLs. When I try to access the URLs provided in the email (and the plan is to drop that URL into our legacy javascript that currently points to the Twitter 1.0 API), i get the error "Authorization is required to perform that action"
I have confirmed countless times that it is set up to "Execute the app as [me]" and "Anyone, even anonymous can access app"
I am not sure what I am missing or what got screwed up.
Turns out, I forgot to set up the callback URL within the Twitter app setup as specified in the source instructions. Oops!
This would explain why it wasn't working even though everything on the Google side was correct.

Resources