Detecting chrome extension update - google-chrome

I have an extension and I did lots of refactoring in my code, I want to publish a new version but in my new code I want to detect when the extension is being updated and do some actions.
I know that with chrome.management I can detect other extension update but I want to detect my own extension update.

You don't need management permission to do that.
You can use chrome.app.getDetails().version To get the last version of your extension using your background page. Than you can store it in localStorage. Every time you load your background page or once every hour you can check if the version matches the one you have on localStorage and detect new installs or updates.
I wonder if there's a better/easier way to do it. But right now this is what I do.
EDIT:
Alternatively you can use this code to get the latest version:
var url = chrome.extension.getURL("manifest.json");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(e) {
if(xhr.readyState == 2 && xhr.status == 200) {
var manifest = JSON.parse(xhr.responseText);
alert("Version: " + manifest.version);
}
};
xhr.open("GET", url);
xhr.send();
extracted from this other SO response.

Related

How do I make Appscript Web App less brittle for use commercially

I've been playing around with the appscript web app thingy and thought I could use it for commercial purposes among a group of say 15 users. However, I get this sporadically:
In the incognito window on the top it works fine. It's logged in as the owner of the app which is me but not really me because I have another account for stuff like this. On the top, is my normal chrome which is logged in as me and as the owner of the account. This is how I set it up
And this is the sharing thing on the my projects
Finally, it draws from this google sheet which for now only I have access to, so hopefully that means no one else can access the data with permission which hopefully means anyone can open it but no one can get access to my precious data necessary to actually use the sheet unless they have access. Of course, in case I'm wrong I have to obscure the url. Anyway, how do I prevent this "Sorry, unable to open the file at this time" error which happens randomly.
It looks like what you are experiencing is an ongoing issue which many users have reported on Google Issue Tracker here and it stems from multiple accounts being logged in.
I suggest you star ★ the issue above and eventually add a comment saying that you are affected by it.
I use Firebase hosting, which has a free tier and is a Google product, for my website.
Go to your Firebase console when logged into a Google account:
https://console.firebase.google.com/?pli=1
I have minimal content in the Firebase index.html file, and then I load more content after the home page loads by using an AJAX POST call to Apps Script and return the content from Apps Script using the Content Service. I think that Firebase hosting is better than a Google Site. A Firebase hosting site requires some set up and some learning, so it's not as easy as Embedding an Apps Script Web App into a Google Site, but for the long term I think it's a better solution.
function doPost(e) {
try{
var html;
var fileName = "MyWebsite";
html = HtmlService.createTemplateFromFile(fileName).evaluate().getContent();
//Get the html file as a string
if (!html) {
html = '<div>There was an error</div>';
}
return ContentService.createTextOutput(html).setMimeType(ContentService.MimeType.TEXT);
}catch(e) {
MailApp.sendEmail(Session.getEffectiveUser().getEmail(), "Load Error", e.message +
"\n\n" + e.stack);
html = '<div>There was an error</div>';
return ContentService.createTextOutput(html).setMimeType(ContentService.MimeType.TEXT);
}
}
In your index.html file you need to call the Web App:
window.getWebSiteContent = function() {
//console.log('getMainContent')
var payload,url;
url = "Put the Apps Script published Web App URL here";
//console.log('url: ' + url)
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
//console.log('onreadystatechange')
if (this.readyState == 4 && this.status == 200) {
//console.log('this.responseText ' + this.responseText);
addTheMainContentToTheWebApp(this.responseText);//Run a function that adds the content
} else if (this.readyState == 4 && this.status !== 200) {
//console.log('Error',this.status)
}
};
xhttp.open("POST",url, true);
xhttp.setRequestHeader('Content-Type', 'text/plain');
payload = {data:{"keyName":"Value"}};
payload = JSON.stringify(payload);
//console.log('payload: ' + payload)
xhttp.send(payload);
}
document.addEventListener('DOMContentLoaded', function() {//Runs when the site is loaded
getWebSiteContent();
});

Run server-side code with google chart select

I have a google visualization table that I'm publishing in a web app.
Background:
I run a script that lists all the documents in a google folder in a spreadsheet. I then push that list into the google table I have published in the web app.
The need:
I want to manage those that same list of documents directly from the web app. I want to be able to to move the document from one folder to another when I select the applicable row on the table.
Two things I have accomplished:
I have a script that will move the document to a specific folder on
the google drive using it's doc id.
I have an event listener on the table so that when you click a row and
then click the delete icon, you get a prompt that asks, "are sure
you want to archive [enter document name]?" When I click ok, I get my
test prompt that says "document archived". When I click no, I get my
test prompt that says "request cancelled". So from this, I know I
have the appropriate code (at least that's how it seems).
What I'm struggling with:
I can't seem to get the codes above to work together. The event listener is providing me the url of the document which I have parsed to give me only the id. This is what I was hoping to use to get the rest of the code to run, but I think because I'm trying to interact with the server-side from the client-side, it's not working. Can anyone help me figure it out? I know that I need to use google.script.run.withSuccessHandler when running a server side script from the client side, but I don't know how it applies to this case the docid I need is being collected on table select. Any help is appreciated and I hope the above makes sense!
// Draw Dashboard
h2dashboard.bind([h2stringFilter, h2typeFilter], [h2chart]);
h2dashboard.draw(h2dataView);
google.visualization.events.addOneTimeListener(h2chart, 'ready', function() {
google.visualization.events.addListener(h2chart.getChart(), 'select', function() {
var selection = h2chart.getChart().getSelection();
var dt = h2chart.getDataTable();
// Get Value of clicked row
if (selection.length) {
var item = selection[0];
var docurl = dt.getValue(item.row, 1);
var docname = dt.getValue(item.row, 0);
var source = dt.getValue(item.row, 3);
// When button is clicked, show confirm box with value
$(document).ready(function() {
$("#hu2archive").on("click", function() {
var answer = confirm("Are you sure you want to archive " + docname + "?");
if (answer === true) {
var archive = DriveApp.getFolderById("FOLDER ID");
var docid = docurl.match(/[-\w]{25,}/); // This is where I'm grabbing the value from the row.
var doc = DriveApp.getFileById(docid);
doc.makeCopy(archive).setName(doc.getName());
source.removeFile(doc);
alert(docname + " has been archived!");
} else {
alert("Request cancelled");
}
});
});
}
});
});
I just got it! What I was having a hard time understanding was how to pass a variable from the client side to code.gs. I have only run a script in code.gs from the client side on button submit but never passed anything back.
So I ended up changing my code to the below which passes the variable I need into a successhandler where archiveDoc is the function in my code.gs and docurl is the name of the variable I need to pass from the eventlistener.
if (answer === true) { google.script.run.withSuccessHandler(onSuccess).withFailureHandler(err).archiveDoc(docurl);
I'm still new to coding so I just learned something new! So thanks Spencer Easton. I did in fact answer my own question.

Chrome extension use report

I have written a chrome extension which I just published to chrome store. I'd like to know all the numbers associated with it. This includes number of installs/number of active users/user activity etc.
Where do I get these numbers from? according to this question there is no way to see the total number of installs: How can I see the number of total installs for my chrome extension?
More importantly is there a way for me to setup Weekly/Monthly emails to get these numbers directly to my inbox?
There's not an official way to do this. Google doesn't provide you detailed stats for your extensions, so if you want to know the details, you should use Analytics.
Follow the tutorial here to set up your Analytics account.
To know the number of people that installs your extension you'll need to set up an Analytics account and link it to your extension, then you can use the chrome.runtime.onInstalled.addListener method to listen to the installation and send a _trackEvent to your Analytics account.
So in your background.js you'll do something like this:
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXXXXX-X']);
// where UA-XXXXXXXX-X is your Analytics Account user number
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = 'https://ssl.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
// now add a listener to the onInstalled event:
chrome.runtime.onInstalled.addListener(function() {
_gaq.push(["_trackEvent", "Installation"]);
});
You can set any combination of "category", "action", "label" after the first "_trackEvent" string calling _gaq.push(["_trackEvent", ...]). Now, every time a user installs the extension, you'll see the number of "Installation" events increase in your Analytics account.

How do I use momentsjs in Google Apps Script?

I'm trying to utilize the momentjs library in Google Apps Script but I'm not clear on how to do so. I'm not sure how to add the library, so obviously running something like the following results in "Reference Error: 'moment' is not defined":
var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
var difference = a.diff(b);
Most people try to use the library with the key ending in 48. That library is pretty dated (it is version 2.9 which is pretty old).
Using eval and UrlFetchApp.fetch moment.js or any other external library can be used easily in google app scripts.
function testMoment() {
eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js').getContentText());
var date = moment().format("MMM Do YY");
Logger.log(date)
}
You may either host the moment.js on your own server, or use a CDN like cloudflare CDN to reference the library.
For cloudflare, here is the page which shows moment.js versions and their urls:
https://cdnjs.com/libraries/moment.js/
As of writing this post 2.18.1 is the latest version.
For the example posted by OP it will look like this:
function testMomentDifference() {
eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js').getContentText());
var a = moment([2007, 0, 29]);
var b = moment([2007, 0, 28]);
var difference = a.diff(b);
Logger.log(difference);
}
The moment script ID for the Google Apps Script IDE has changed. It is now "15hgNOjKHUG4UtyZl9clqBbl23sDvWMS8pfDJOyIapZk5RBqwL3i-rlCo"
You can add moment and moment.tz to app scripts by creating a new Script file and adding the following code:
var cacheExpire = 3600;
var momentCache = "momentCache";
var momentUrl = "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"
var momentTzCache = "momentTzCache";
var momentTzUrl = "https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.16/moment-timezone-with-data-2012-2022.min.js"
useCachedOrLive(momentCache,momentUrl);
useCachedOrLive(momentTzCache,momentTzUrl);
function useCachedOrLive(cacheToCheck, url){
var cache = CacheService.getUserCache();
var cachedData = cache.get(cacheToCheck);
console.log(cacheToCheck);
if(cachedData !== null){
console.log("using cached " + cacheToCheck)
eval(cachedData);
}
else
{
console.log("getting live " + cacheToCheck);
var response = UrlFetchApp.fetch(url).getContentText();
cache.put(cacheToCheck, response, cacheExpire);
eval(response);
}
}
This uses the cache service to reduce round trip calls and you can modify it to include a subset of data if you want.
Thanks to apadana for getting me started!
There is a better and best way to use moment
Do not use UrlFetchApp, to avoid quota exceeded, caching, and server issues
Download moment.min.js and momemt-timzone.min.js in last versions
and integrate the full files in apps script like the below screen
There is no problems in long run with this approach, just update the files any time when you need.
After adding the two files, just publish a new version and include it in any other script
For example:
I will create a script with name "MomentAPI" and include the two
files mentioned, and publish a new version.
in other script with name "myScript" I will include the library
"MomentAPI" with its script id as known
then will use it like the below examples
const moment = MomentAPI.moment; // init the library
const start = moment().startOf('day').toDate(); // Dec 06 00:00:00
const end = moment().endOf('day').toDate(); // Dec 06 23:59:59
const d = moment(1767139200000).tz('America/New_York').format('ha'); // 7am EST
Using external Javascript library is not so easy... Depending on the context in which you want to use it (a webapp of a document embedded script) the approach will be different.
I didn't try it in client JavaScript and I'm not sure caja will allow it but I found this post that shows a possible way to include it using a Google Script Library that a user has build and if I read the post it seems to work...
The "user" is a Google developper so he knows for sure what he is talking about ;) please update here if it worked for you.

Verifying file download with Selenium

I need to use selenium to verify a download. I need to click on the download file link and check that it is downloadable or not. (Means download is starting or not)
I need to create a simple HTML script for this. But as Selenium does not recognize the 'Save As' dialog box for file download, I am not able to proceed.
Is there any solution within Selenium for this. I cannot use any other 3rd party tool as this is a part of centralized UI testing script.
Thanks in advance.
My solution (in C#) is get the Url of the file to download and any cookie and make the request using WebClient:
var testLink = seleniumDriver.FindElement(By.LinkText("Link to file"));
var pdfHref = testLink.GetAttribute("href");
var manage = seleniumDriver.Manage();
var cookies = manage.Cookies.AllCookies;
using (var wc = new WebClient())
{
foreach (var cookie in cookies)
{
var cookieText = cookie.Name + "=" + cookie.Value;
wc.Headers.Add(HttpRequestHeader.Cookie, cookieText);
}
var fileResult = wc.DownloadData(new Uri(pdfHref));
// or use wc.DownloadString or wc.DownloadFile
// Do any test required
}