Creating a hyperlink in active cell from uploaded file - hyperlink

I'm designing a shared Google Sheets for our team to keep track of each piece of content we produce. I want to implement a feature that allows people to upload a preview clip and have a hyperlink automatically created within the active cell.
My script so far serves up HTML as a user interface with a file upload and name entry. This part works fine and allows anyone to upload straight to Google Drive.
I've been having trouble getting it to automatically create a hyperlink in the active cell to the uploaded file. Been searching around, but haven't had a great deal of luck.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('File Upload')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Upload A File');
}
function uploadFiles(form) {
try {
var dropbox = "Clips";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}

My suggestion is to modify the return value from uploadFiles() to be an object, then use the URL to populate a spreadsheet HYPERLINK() formula.
return "File uploaded successfully " + file.getUrl();
Becomes:
return {
result: "File uploaded successfully",
fileURL: file.getUrl(),
fileDesc: file.getDescription() // Could be other values
};
Next, a function that sets the formula. This server-side function would be called with the values to be used in the formula, which were previously returned from uploadFiles(). I'm assuming this is from your client-side JavaScript, but that's just a guess, since you didn't include that in your question.
function setHyperlink( fileURL, fileDesc ) {
var formula = '=HYPERLINK("' + fileURL + '","' + fileDesc + '")';
SpreadsheetApp.getActiveCell()
.setFormula( formula );
return true;
}

I ended up solving this issue using the GAS Properties Service - creating 2 new User Properties to contain URL and Name data.
I also found a few issues with getActiveCell - it kept placing the link in A1. Although I had used Google's suggested method for returning the active cell, I was able to use the fix suggested here:
http://bit.ly/20Gc7l6
Here's my final script
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('File Upload')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Upload A File');
}
function uploadFiles(form) {
try {
var dropbox = "Blacksand Clips";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription(file.getDescription());
var userProperties = PropertiesService.getUserProperties();
var link = file.getUrl();
var name = file.getName();
userProperties.setProperty('link', link);
userProperties.setProperty('name', name);
setHyperlink();
return "File uploaded successfully ";
} catch (error) {
return error.toString();
}
}
function setHyperlink() {
var userProperties = PropertiesService.getUserProperties();
var link = userProperties.getProperty('link');
var displayName = userProperties.getProperty('name');
var value = 'hyperlink("' + link + '","' + displayName + '")'
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell().activate();
cell.setFormula( value )
return true;
}

Related

File download of server -generated file from button asp.net mvc

OK, this sounds dumb even to me, but I am clearly having a "bad brain day" and need help.
On a button click, I want to generate a file based on parameters taken from 2 ViewData fields and a checkbox control, and have the file be downloaded/displayed, just as you get with a fixed link.
Most of it is going fine, the controller method passes back a file like so: Return File(filePath, "text/csv") - but then what? How do I connect that to the button and have the file download/open dialog come up?
I feel I am missing something really simple. Just calling the controller via ajax seems to do nothing... the code is called but I see no results
***** EDIT: ******
The following gets me a file automatically downloaded, but with the name "download" - I want to offer the user the choice to open or download, and to set the filename - how do I do that?
serialize = function (obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var params = {
ID1: '#ViewData("ID1")',
ID2: '#ViewData("ID2")',
flag: getFlag()
};
var actionUrl = ('#Url.Action("ProduceReport", "Report")');
actionUrl += "/?" + serialize(params);
window.open(actionUrl);
* 2nd edit *
Controller code - this produces a file and returns the path. After the call to ProduceReport The file is there on that path, this I have checked. It is used in production to email the file (works fine).
public FileResult ProduceReport(int ID1, int ID2, bool flag = false)
{
var filePath = ExcelReports.ProduceReportExcel(Models.UserInfo.GetCurrentUserID, ID1, ID2, flag);
return File(filePath,"application/vnd.ms-excel");
}
The acceptable compromise that I found, to at least get the file downloaded. I will have to do further research to see if I can print it automatically.
Javascript:
serialize = function (obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var params = {
ID1: '#ViewData("ID1")',
ID2: '#ViewData("ID2")',
flag: getFlag()
};
var actionUrl = ('#Url.Action("ProduceReport", "Report")');
actionUrl += "/?" + serialize(params);
window.location.href = actionUrl;
Controller: Note 3rd parameter on the File() call
public FileResult ProduceReport(int ID1, int ID2, bool flag = false)
{
var filePath = ExcelReports.ProduceReportExcel(Models.UserInfo.GetCurrentUserID, ID1, ID2, flag);
return File(filePath,"application/vnd.ms-excel",System.IO.Path.GetFileName(filePath));
}

Cordova / Ionic - Download file from InAppBrowser

The scenario goes like this: I open a website in InAppBrowser, after the user ends with the work over there, the site generates a .pdf for the user to download, the problem is that the pdf does not download, it opens it in the browser.
Is there a way to make it download from the InAppBrowser? I'm currently working on an iOS app, so the solution would be better for iOS.
Thanks in advance.
Following #jcesarmobile advices this is what I came up with:
First I had to install the cordova-plugin-file-transfer
Open URL
var url = "http://mi-fancy-url.com";
var windowref = window.open(url, '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
Create a listener on that windowref for a loadstart event and check if what's being loaded is a pdf (that's my case).
windowref.addEventListener('loadstart', function(e) {
var url = e.url;
var extension = url.substr(url.length - 4);
if (extension == '.pdf') {
var targetPath = cordova.file.documentsDirectory + "receipt.pdf";
var options = {};
var args = {
url: url,
targetPath: targetPath,
options: options
};
windowref.close(); // close window or you get exception
document.addEventListener('deviceready', function () {
setTimeout(function() {
downloadReceipt(args); // call the function which will download the file 1s after the window is closed, just in case..
}, 1000);
});
}
});
Create the function that will handle the file download and then open it:
function downloadReceipt(args) {
var fileTransfer = new FileTransfer();
var uri = encodeURI(args.url);
fileTransfer.download(
uri, // file's uri
args.targetPath, // where will be saved
function(entry) {
console.log("download complete: " + entry.toURL());
window.open(entry.toURL(), '_blank', 'location=no,closebuttoncaption=Cerrar,toolbar=yes,enableViewportScale=yes');
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
true,
args.options
);
}
The problem i'm facing now is the path where it downloads, I just can't open it. But well, at least file is now downloaded. I will have to create a localStorage item to save the paths for different files.
Many validations are missing in this steps, this was just an example I made quickly to check if it works. Further validations are needed.
Open you window using IAB plugin and add an event listener
ref = window.open(url, "_blank");
ref.addEventListener('loadstop', loadStopCallBack);
In the InAppBrowser window call the action using https://xxx.pdf">documentName
Implement the loadStopCallBack function
function loadStopCallBack(refTemp) {
if(refTemp.url.includes('downloadDoc')) {
rtaParam = getURLParams('downloadDoc', refTemp.url);
if(rtaParam != null)
downloadFileFromServer(rtaParam);
return;
}
}
function getURLParams( name, url ) {
try {
if (!url)
url = location.href;
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(url);
return results == null ? null : results[1];
} catch (e) {
showSMS(e);
return null;
}
}
After create a download method
function downloadFileFromServer(fileServerURL){
try {
var Downloader = window.plugins.Downloader;
var fileName = fileServerURL.substring(fileServerURL.lastIndexOf("/") + 1);
var downloadSuccessCallback = function(result) {
console.log(result.path);
};
var downloadErrorCallback = function(error) {
// error: string
console.log(error);
};
//TODO cordova.file.documentsDirectory for iOS
var options = {
title: 'Descarga de '+ fileName, // Download Notification Title
url: fileServerURL, // File Url
path: fileName, // The File Name with extension
description: 'La descarga del archivo esta lista', // Download description Notification String
visible: true, // This download is visible and shows in the notifications while in progress and after completion.
folder: "Download" // Folder to save the downloaded file, if not exist it will be created
};
Downloader.download(options, downloadSuccessCallback, downloadErrorCallback);
} catch (e) {
console.log(e);
}
}
you can get the plugin here https://github.com/ogarzonm85/cordova-plugin-downloader
it Works and was too easy

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.

Error in File downloading file from a folder in MVC2

I am encountering a problem in getting the download prompt. In the below code first am allowing the user to upload a file to compress. Once the file is compressed the user should be provided with the compressed files. But in the below code download prompt doesn't appears neither it shows any error. Please help me by correcting my code
The view code:
function CompressFile(box) {
var file = document.getElementById('fileComp');
if (file.value == "") {
alert("Choose a file to upload");
return false;
}
dhtmlx.modalbox.hide(box);
var fd = new FormData();
fd.append('file', file.files[0]);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/FileUpload/Compress', true);
xhr.send(fd);
}
The controller code:
public ActionResult Compress(HttpPostedFileBase file)
{
var supportedType = new[] { "pdf" };
var fileExt = System.IO.Path.GetExtension(file.FileName).Substring(1);
var filename = Path.GetFileNameWithoutExtension(file.FileName) ?? "";
if (file.ContentLength > 0 && supportedType.Contains(fileExt))
{
string filePath = Path.Combine(HttpContext.Server.MapPath(_uploadPDF), Path.GetFileName(file.FileName));
file.SaveAs(filePath);
PdfReader reader = new PdfReader(filePath);
string name = DateTime.Now.ToString("ddMM_HHmmss");
name = Server.MapPath(_fileUploadPath + name + ".pdf");
PdfStamper stamper = new PdfStamper(reader, new FileStream(name, FileMode.Create), PdfWriter.VERSION_1_5);
stamper.FormFlattening = true;
stamper.SetFullCompression();
stamper.Close();
string fn = System.IO.Path.GetFileName(name);
return base.File(name, "application/pdf",fn);
}
else
{
return View();
}
}
The problem is that you're using Ajax. You can't download a file through Ajax. You need to do a regular POST to the ActionMethod. That way the browser can send you back the file and prompt the user where he wants to save it.

Java scripting in SharePoint custom lists

In SharePoint lists, you are not permitted to upload files which have any kind of special characters in their file name. (For eg: file&.doc cannot be uploaded)
So I have a JavaScript code that validates the file name on submitting the list and creates a dialogue box that tells the user to rename the files before uploading and only then you can proceed.
My issue is, the code only works for 1 document, if more than 1 document is uploaded. it does not validate the second item. I need help so that I can upload n number of items and it validates eac
<Script type="text/javascript">
function PreSaveAction()
{
var attachment;
var filename="";
var fileNameSpecialCharacters = new RegExp("[~#%&*{}<>;?/+|\"]");
try {
attachment = document.getElementById("idAttachmentsTable").getElementsByTagName("span")[0].firstChild;
filename = attachment.data;
}
catch (e) {
}
if (fileNameSpecialCharacters.test(filename)) {
alert("Please remove the special characters like ~#%&*{}<>;?/+|\ from the file attachment name and reattach the file.");
return false;
}
else {
return true;
}
}
</script>
allow only certain files in 2007 sharepoint list
Edit: included code from comment:
<Script type="text/javascript">
function PreSaveAction()
{
var attachment;
var filename="";
try
{
attachment = document.getElementById("idAttachmentsTable")
.getElementsByTagName("span")[0]
.fi‌​rstChild;
filename = attachment.data;
}
catch (e) { }
if (!filename.match(/^(.+?\.xlsx?)$/i))
{
alert("Please attach only excel files.");
return false;
}
else
{
return true;
}
}
</script>
You cant loop through the list of documents? Put all the file names into a structure / Array / something and look at them all?
I created a modified version that will check for all attachments. The one liste here, only checks for the first attachment.
Here is mine
function chechAttachments() {
var spanTag;
var filename="";
var fileNameSpecialCharacters = new RegExp("[~#%&*{}<>;?/+|\"]");
try {
spanTag = document.getElementById("idAttachmentsTable").getElementsByTagName("span");
for (var i = 0; i < spanTag.length; i++) {
filename = spanTag[i].innerHTML;
}
}
catch (e) {
}
if (fileNameSpecialCharacters.test(filename)) {
alert('Attachments cannot contain special characters such as "[~#%&*{<>;?/+|\"]".\n\nPlease remove the special characters from the file attachment name.');
return false;
}
}

Resources