Determine if active tab contains an editable Google Doc - javascript

Suppose my extension has obtained the URL for the current active tab using the method suggested in How can I get the current tab URL for chrome extension?, e.g.
chrome.tabs.query({
active: true,
lastFocusedWindow: true
}, function (tabs) {
// use first tab to obtain url
var tab = tabs[0];
var url = tab.url
});
How can I determine if the URL refers to a Google Doc to which I have editing rights? The distinction between ownership and being an invited collaborator is not important for this application. I'm interested only in Docs as opposed to Spreadsheets or Forms.
For context on what I'm trying to develop, see: How to manually generate notifications to a Google Doc collaborator?

Alternate answer, based on the Google Drive API rather than the Google Docs UI.
Before doing any of this, make sure to declare permissions in the manifest (to only match URLs that look like docs.google.com/document/*).
Here is a broad overview of the steps you could follow:
GET a
file,
which will return some metadata. You can use the URL you have to extract the relevant ID which is used in the GET request.
Use this metadata file resource to retrieve a permissions resource
In the permissions resource, look at the role attribute: it will be either owner, reader, or writer. You will not have editing rights if you are a reader, but should have editing rights otherwise.

Here is a side by side view of a google doc, where I created a doc, generated a sharing link, and opened it in a browser where I was not signed in to google. I would suggest using a content script to insert a "find" function which would return either true or false if it can locate the "view only" button in the DOM ("view only" meaning you do not have edit permissions). You could make the content script match URLs that look like docs.google.com/document/* only.
Caution: google changes UI pretty frequently so this may not be future-proof. Try inspecting the source of google docs in both situations to look for more clues.
Side by side view:
Source code in the chrome devtools:

Related

Update chrome extension manifest permissions from options page

I am trying to update the permissions in the chrome extension manifest file from the options page.
Basically the user should be able to input the url for the extension to run on and that url will update in the extensions manifest file.
I am currently storing all my options using chrome.storage.sync for use in multiple files.
I am looking for a secure solution to give only the chosen url access. Any suggestions?
That's not possible (to update the manifest).
However, the particular use case you explain is:
Have a list of "allowed" websites.
When the extension is invoked by pressing the button, if the website is allowed - inject a content script that does something.
In this case "activeTab" permission and Programmatic Injection should solve your problem.
You do not declare any content scripts in the manifest. This ensures code runs only when you want to.
You do not declare any host permissions in the manifest. Your extension will ONLY work on the current tab at the moment of Browser Action press.
You ask the user for allowed URLs and store them in chrome.storage.
When your extension is invoked using the Browser Action, you can query the currently active tab and you will get its URL (because of the "activeTab" permission).
Your logic then compares it to stored whitelisted URLs.
If there's a match - you use chrome.tabs.executeScript to inject your content script.
If there's no match - do nothing, or somehow ask user to confirm whitelisting the new domain.
Here's some sample code:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var currentTab = tabs[0];
// Pseudocode
if (whitelisted(currentTab.url)) {
chrome.tabs.executeScript(currentTab.id, {file: "content.js"});
} else {
// Do nothing or show some warning
}
});
Alternatively, you can look at Optional Permissions API.

Showing documents from Google Drive on webpage

Is it possible to show the documents from my drive on a webpage? I want the user to be able to click the document and download it, directly from my drive. How would I go about doing this? Thank you for your suggestions.
The fastest and easiest solution is to embed the folder using an iframe (no javascript needed). Obviously this is also the least flexible solution, although you can use CSS to change the layout of the iframe contents (see below).
Google Drive won't allow embedding of the url you would normally use. It has its X-Frame-Options header set to "SAMEORIGIN", preventing use in an iframe. So you have to use the following link, which will allow embedding:https://drive.google.com/embeddedfolderview?id=DOCUMENT_ID#VIEW_TYPE
DOCUMENT_ID is the id that is mentioned in the normal share link (which looks like https://drive.google.com/folderview?id=DOCUMENT_ID), so you can just copy that from there.
VIEW_TYPE should be either 'grid' or 'list', depending on your preference.
And if you need to change the style of the iframe content, take a look at this solution.
For HTML/JavaScript solution, look at the following links:
https://developers.google.com/drive/quickstart-js
https://www.youtube.com/watch?v=09geUJg11iA
https://developers.google.com/drive/web/auth/web-client
Here's the simplest way using JavaScript, most of the complexity is in
your WebApp authorization. The example below reads files IDs, names and description in a folder you specify.
- go to: https://cloud.google.com/console/project
and create a new project "xyz"
- Select "APIs & auth", disable the ones you don't need, enable "Drive API"
- Select "Credentials",
push "CREATE NEW CLIENT ID" button
x Web Application
Authorized Javascript origins: "https://googledrive.com/"
Authorized redirect URI: "https://googledrive.com/oauth2callback"
it will result in:
Client ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
Email address: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com
Client secret: xxxxxxxxxxxxxxxxxxxx
Redirect URIs: https://googledrive.com/oauth2callback
Javascript Origins: https://googledrive.com/
- in the code below, replace
CLIENT_ID with xxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com
FOLDER_ID with the ID you see in the folder address line,
https://drive.google.com/?tab=mo&authuser=0#folders/xxxxxxxxxxxxxxxxxxx
- run it, authorize
I don't know if you read JS, the code can be followed from bottom up, I made is as simple as possible.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
var FOLDER_ID = '.xxxxxxxxxxxxxxxxxx'; // the folder files reside in
var CLIENT_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
var SCOPE = //'https://www.googleapis.com/auth/drive';
[
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file', // for description,
];
function rsvpCB(resp) {
var picAlbumLst = '<ul>\n';
for (i=0; i<resp.items.length; i++)
picAlbumLst += (
' <li>'+resp.items[i].id+', '+resp.items[i].title+', '+resp.items[i].description+'</li>\n');
picAlbumLst += "</ul>\n";
$('#container').append(picAlbumLst);
}
function rqstCB() { //test # https://developers.google.com/drive/v2/reference/files/list
var rv = gapi.client.drive.files.list({
'q': '"'+FOLDER_ID+'" in parents and trashed = false',
'fields' : 'items(id,title,description)' //'items(id,title,description,indexableText)'
}).execute(rsvpCB);
}
// authorization server reply
function onAuthResult(authResult) {
var authButton = document.getElementById('authorizeButton');
authButton.style.display = 'none';
if (authResult && !authResult.error) { // access token successfully retrieved
gapi.client.load('drive', 'v2', rqstCB);
} else { // no access token retrieved, force the authorization flow.
authButton.style.display = 'block';
authButton.onclick = function() {
checkAuth(false);
}
}
}
// check if the current user has authorized the application.
function checkAuth(bNow) {
gapi.auth.authorize({'client_id':CLIENT_ID, 'scope':SCOPE, 'immediate':bNow}, onAuthResult);
}
// called when the client library is loaded, look below
function onLoadCB() {
checkAuth(true);
}
</script>
<script src="https://apis.google.com/js/client.js?onload=onLoadCB"></script>
<body style="background-color: transparent;">
<input type="button" id="authorizeButton" style="display: none" value="Authorize" />
<div id="container">
</div>
</body>
This should be done with Google API. You can search google drive php api list files on google. And also I found this and this on SO.
Here are some main points:
Do you want anyone with the URL to be able to see your document? You can share a document as public to anyone on the internet. Plus you can set read access to specific folders. Just right click a Google Doc file, and choose 'Share' from the short cut menu.
I'm assuming you want people to download your docs, even when you are not signed in. This is called 'Offline Access', and is one of many terms you'll need to figure out in order to do all of this with a program.
If you only want to give read access to the user, using JavaScript, jQuery, etc on the front end is a viable option. You can also do this in PHP, it's just a matter of personal preference.
To do all of this in code, you need to grant authorization to read your files. The oAuth2 process has multiple steps, and it's good to understand the basic flow. Setting up the code and the webpages to initially grant authorization, then retrieve and store the tokens can get confusing.
Your Google Project has a setting for where the origin of the authorization request is coming from. That is your website. But if you want to develop and test locally, you can set the Javascript Origins to http://localhost
How much time do you have, and how much programming experience? Would it be easier to give the user a few lines of instruction to "Manually" download your file, rather than program the authorization check?
Putting the document into your webpage is the easy part.
In order to embed a Google doc in your website, go to your Google Drive, open a document and choose File then Publish to Web, and you will be given an HTML iFrame Tag that can be embedded into you web page. You can change the height and width of the iFrame to match the document size. iFrame Instructions W3Schools
Downloading your document can be done very easily from the online version of a shared document just by choosing FILE and then DOWNLOAD AS from the menu.
To get up and running fast, just give the user a couple lines of instructions on how to download "Manually", then see if you can program the code.
Provide a link to your shared document instead of programming the button, and then work on the code.
Search Git Hub for Google Drive, you might find something there.
Some of the official Google code examples are way more complicated than you need, and will take a long time to figure out. The code examples in the documentation pages are simpler, but are almost never complete functioning code examples. You'll need to put lots of pieces of the puzzle together to make it work.

How to open email by x-gm-msgid in Gmail with Javascript

I'm writing an extension which surfaces links to gmail messages. As the UI loads right in Gmail, I should be able to click on one of these links and have Gmail load it (without refreshing). I have "x-gm-msgid" available and theoretically, I should just be able to navigate to "https://mail.google.com/mail/u/0/#inbox/[x-gm-msgid]".
I've tried using
location.hash = "#inbox/[x-gm-msgid]"
I've tried using
history.pushState(null, null, "/mail/u/0/#inbox/[x-gm-msgid]")
Neither of which works. Gmail just thwarts any attempt to change the URL (unless it is done via user interaction)
Any thoughts on how to get around this restriction?
chrome.tabs.update should work.
Modifies the properties of a tab. Properties that are not specified in updateProperties are not modified. Note: This function can be used without requesting the 'tabs' permission in the manifest.

open custom url scheme via Spotify Apps API

From a Spotify app I want to communicate with a native application that has been registered with a custom URL scheme. I am testing with a clickable anchor tag
open custom url scheme
as well as javascript code
location.href = "myscheme:/test";
which both work fine from any browser. At first, nothing happened when I clicked the link/ran the JavaScript in Spotify. After extending the permissions in manifest.json to
"RequiredPermissions": [
"https://*",
"http://*",
"myscheme:/*"
]
I am getting this page in the content view for both cases (click and JS)
<head></head>
<body>Error -302 when loading url myscheme:/test</body>
and the console output says
I [mainview:6886] Load complete (1) url:
I [mainview:6886] Load complete (0) url: cef-error:
Update: For the scheme mailto: this seems to work just fine. Even without an explicit entry to RequiredPermissions.
Update 2: In more recent versions (e.g. 0.8.4.124) clicks on links with custom URIs have no effect to the content anymore. The log states:
W [CefAppInstance.cpp:49 ] App spotify:app:tutorial is not allowed to access resource: myscheme:/test
The mailto: still to works without explicit RequiredPermissions.
Do you have any idea?
Unfortunately, as far as I'm aware this isn't supported in the Apps API.

Google Analytics testing/sandbox environment?

Is there any Google Analytics testing/sandbox environment for testing your JS custom code before putting it to live system?
I don't want to use my real tracking ID to see if everything is correct on my dev. environment, neither I want to put my code untested live...
Is there any techniques or maybe some fake Analytics tracking lib I could use for testing?
The Google Analytics Debugger Chrome Extension is very helpful in testing Google Analytics code. The extension outputs the data sent to Google Analytics to the JavaScript Console Window. The days of you...waiting around...hoping/praying to see your test Pageviews in Google Analytics are over.
Below is an example of some of the output the extension prints to the JavaScript Console Window:
Track Pageview
Tracking beacon sent!
Account ID : UA-2345678-90
Page Title : About
Host Name : www.yourdomain.org
Page : /about
Referring URL : -
Language : en-us
Encoding : UTF-8
Flash Version : 11.1 r102
Java Enabled : true
Screen Resolution : 1680x1050
Color Depth : 16-bit
Ga.js Version : 5.2.4d
Cachebuster : 476867651
I believe it is possible, but you have to tell it to not use the domain when setting the cookie...
var pageTracker = _gat._getTracker("UA-12345-1");
pageTracker._setDomainName("none");
pageTracker._trackPageview();
And you probably have to use a legitimate tracker ID.
Also, be sure to see Analytics Customizations: Using a Local Server
Why don't you just create a new tracking code / profile in GA? That way you can see the results on your dev server and then switch to the real tracking number when you move to live.
I think a lot has changed since the question was asked, but I believe I should add this here just for the new visitors since it is not in the answers.
Google Analytics now has a Sandbox Account that you can create. Check out the source for the direct announcement by them.
Short instructions from the link:
If you already have a Google Analytics account, you'll need to create a new one as your "sandbox" by following these instructions:
Click Admin at the top of any Analytics page.
In the Account column, click the menu, then click Create new account.
Follow the instructions.
Source:
https://groups.google.com/forum/#!category-topic/digital-analytics-fundamentals/6EYCkNdE2No
I think it should be done with "views" in 2019.
Create views for development and production https://support.google.com/analytics/answer/1009714?hl=en
Create a custom dimension "environment" = "test" / "prod". Send it from website/app.
Create filters by custom dimension "environment" on view level https://www.bounteous.com/insights/2015/10/16/filtering-session-user-custom-dimensions-google-analytics/
Maybe for some projects filters can be done by URL instead of custom dimensions.

Categories

Resources