How can I get content from google docs for email body in Html format in app script as earlier I was using classic google sites for getting body content of the email and now the classic sites are shutting down. Or do you know any alternative for this . Earlier I was using code for getting content.
SitesApp.getPageByUrl(spSignURL).getHtmlContent()
You may export the document as HTML. To do so you may use the following function:
function exportAsHtml(documentId) {
DriveApp.getRootFolder() // Makes Apps Script get the right permissions
const result = UrlFetchApp.fetch(`https://www.googleapis.com/drive/v3/files/${documentId}/export?mimeType=text%2Fhtml`, {
headers: {
"Authorization": `Bearer ${ScriptApp.getOAuthToken()}`
},
muteHttpExceptions:true,
})
const content = result.getContentText()
if (result.getResponseCode() >= 400) {
console.error(JSON.parse(content))
throw new Error("Exception when exporting as HTML")
}
return content
}
The first line of the function makes it so Apps Script grants you the necessary permissions. Alternatively you can manually set all the permissions you are using at the manifest.
It's worth noting that email HTML is not 100% the same as web HTML, so you may need to clean the result a bit depending on your use case.
References
UrlFetchApp.fetch(url, params) (Apps Script reference)
Files: export (Google Drive API reference)
Related
I've tried to use the microsoft teams client SDK to get access to the current context of the tab. As of yet I haven't been able to get the getContext callback to run let alone return a context that I can use in any meaningful way.
I've tried to create a static html page that uses the client SDK by embedding the script and then log the context of the object. The SDK properly returns an object of the expected shape, but using initialize() then getContext() does nothing. I'm making this website as a tab inside of Microsoft teams creating a new tab and making it a website tab.
<p>hello World!</p>
<script src="https://statics.teams.microsoft.com/sdk/v1.4.2/js/MicrosoftTeams.min.js" crossorigin="anonymous"></script>
<script>
console.log(microsoftTeams);
microsoftTeams.initialize();
microsoftTeams.getContext((context) => console.log(context));
</script>
This is the static page I'm using to try and get context logged out to the console.
const http = require("http");
const fs = require("fs");
this.html;
fs.readFile("./src/index.html", (err, html) => {
if (err) {
throw new Error(err);
} else {
this.html = html;
}
})
http.createServer((req, res) => {
res.write(this.html);
res.end();
}).listen(7777);
This is my server I'm using to return the static html
I'm using ngrok to provide a tunnel from the web to my local server on port 7777. I can get the page to load just fine, but have yet to get the getContext() to run my callback function.
I expect to be able to get the context of the teams tab in the callback of the getContext() function, but that function never runs.
Moving answer from Comments section:
Tab created using default Website App doesn't get the Teams context, it needs to be a trusted URL. You need to build custom Tab to get context for your Microsoft Teams tab.
Please take a look at steps to create Teams App manifest using App Studio.
In the default application specified Hello World with Node.js if you put this script in the end of body tag.
console.log(microsoftTeams);
microsoftTeams.initialize();
microsoftTeams.getContext((context) => console.log(context));
Now you have to run this application in Teams environment only then this context method will get a value and not on regular html page.
I am trying to communicate my web page script with my content script of my web extension with the code below
Web Page Script
const browser = window.browser || window.chrome;
browser.runtime.sendMessage(message,
function (response) {
console.log(response);
}
);
However, I keep getting the error TypeError: browser is undefined. The same goes if I use chrome.runtime.sendMessage() instead.
How am I supposed to use this method?
The issue here is that user/webpage scripts (unprivileged scripts) don't have access to JavaScript API for security purposes and browser, chrome are part of JavaScript APIs which can only be accessed by privileged scripts like web extension's background scripts and content scripts (again content scripts don't have access to all the JavaScript APIs). Basically, if you need to send data from web page script to background script, CustomEvent should be used to send data to a content script which acts as a bridge and from there send that data to background script using browser.runtime.sendMessage. PFB sample code
window.onload = function(){
document.dispatchEvent(new CustomEvent("myEvent",{
detail:["Hello","World"]
}));
}
contentscript.js
document.addEventListener("myEvent", function (event) {
browser.runtime.sendMessage({
data: event.detail
});
background.js
browser.runtime.onMessage.addListener(function (message) {
data = message.data;
// do stuff
});
This question already has answers here:
Optionally inject Content Script
(3 answers)
Closed 7 years ago.
I am writing an extension that has options which let users decide which sites they want the extension to run on.
Say the user has this site in the options
site action
stackoverflow.com/* change background css to blue
google.com/* change background css to green
I store these string in the options. When the content_script runs should I retrieve these strings from options, loop through each one, parse with a urlParser into parts, turn each part into a regex (escaping everything but *), and compare it with document.URL? I recently read that this kind of user options validation for Urls should be done through a background script too so I'm not sure which way to go or if there's a more obvious way to do it.
I think extensions like Adblocker and Vimium seem to have this functionality but for deciding which sites not to run on. I want to figure out how to decide which sites to run on.
Update to the Question: Since my content_script needs to run at document_start (before the page is loaded since it deals with editting the page appearance) as a content_script, will the background page be able to execute the content_script before the webpage is loaded at all?
Validated a web page's url should be "validated" via a background page because the user's options will be hosted in local storage in the context of the background page. Here is what I would do... (although it's more of a suggestion that an answer).
I am not sure how the actions on the right column of your list factor into your question, sorry.
(Also note, you would need to incorporate a library (external or self-written) that can parse globs into regex.)
manifest.json
permissions: ["tabs", "storage", "webRequest", "<all_urls>"]
background.js
//allow the webrequest to run on all urls
var filter = { urls: "<all_urls>" };
//receives url information from webrequest listener
function listen(details) {
getUserOpts()
.then(function(arrayOfWhitelistUrls) {
//you can't use globs here, need to use more powerful filtering mechanisms
if (arrayOfWhitelistUrls.indexOf(details.url) > -1) {
message();
}
});
}
//returns a promise containing user defined whitelist urls from background local storage
function getUserOpts() {
return new Promise(function(res, rej) {
chrome.storage.get("whitelist", function(data) {
//you are saving all localhost data as a string, so you need to parse it first
res(JSON.parse(data));
});
});
}
//messages content script and allows execution
function message() {
chrome.tabs.query({active: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {permission: true});
});
}
chrome.webRequest.onBeforeRequest.addListener(listen, filter)
contentscript.js
function listen(message) {
if (message.permission) {
if (message.permission === true) {
init();
}
}
}
//listen for message
chrome.runtime.onMessage.addEventListener(listen);
So the order in which things run is like:
background page listens to each web request
on each web request, the background page asynchronously fetches user options from local storage
if the url of the current tab passes your filter, message your content script
the content script receives the message and then runs
There might be an easier way to do this; the downside to this method is that you need to include the permission gateway in every content script you have.
I am building a search engine as a start-up project in Web Development. The search engine takes a string and queries the Wiki and Twitter API. I have been working on it for days and, I believe, I have found a nice, clean way to implement it.
BoyCook's TwitterJSClient
In his code (which is beautifully written) he has set up a Twitter function which takes in a config variable and sets up the authorization for us. Is there something it is missing? I have been through it and it all looks great. I am new to Javascript and might be missing something..
My code:
var error = function (err, response, body) {
console.log('ERROR [%s]', err);
};
var success = function (data) {
console.log('Data [%s]', data);
};
var config = {
"consumerKey": "{Mine}",
"consumerSecret": "{Mine}",
"accessToken": "{Mine}",
"accessTokenSecret": "{Mine}",
"callBackUrl": ""
}
var Twitter = require('twitter-node-client').Twitter;
var twitter = new Twitter(config);
twitter.getSearch({'q':'Lebron James','count': 10}, error, success);
Can anyone help? Have you done this before and know an easier way? Has anyone been able to get it working using postMessage()?
And yes... the origin is using HTTPS protocol. See: JBEngine. My app permission (on Twitter) is set to read only.
[EDIT] Should probably also mention that I glob'd it all together with browserify and am running the script client-side.
I have a packaged app that embeds a app-local page in an iframe (to embed libraries doing forbidden stuff).
My sandboxed page wants to make an xmlhttprequest to a relative URL (so still in the same extension), but it is refused with the following message:
XMLHttpRequest cannot load
chrome-extension://nilibhiopchihkgnnecfblfjegmogpgn/libs/fonts/miss_fajardose/MissFajardose-Regular.ttf.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
To tell the truth, I found the relevant documentations:
http://developer.chrome.com/apps/manifest/sandbox.html
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox
But they make no sense to me, maybe it's the mix of colors and ADD.
A bit of context: I am using the same code inside my chrome web app and on the internet, in this instance I am loading a font, typesetting something and computing a toolpath for contouring the text. If the page is the chrome app there is a button to send it to the router, if it is on the web you can just see the toolpath.
After about a half day of my life poking around, here's the best workaround I found. From sandboxed page, postmessage to parent asking for local file to be loaded:
window.top.postMessage({ XMLFile: "levels/foo.xml" }, "*");
In nonsandboxed page, initiate async load of file, then call back down to the sandboxed page with the string version of the file:
document.body.onload = function() {
// Listen for request messages from child window
window.addEventListener("message", function (event) {
if (event.data.XMLFile) {
// Load the requested XML file, must be async
var xhttp = new XMLHttpRequest();
xhttp.open("GET", event.data.XMLFile, true);
xhttp.send(null);
// After loading, pass the resulting XML back down to sandboxed page
xhttp.onload = function (e) {
document.getElementById("idSandbox").contentWindow.postMessage({ sResponseText: xhttp.responseText }, '*');
}
}
} );
}
Returning to the sandboxed page, when you receive the xml response text, convert it back into a DOM object for parsing:
// Receive messages from containing window
window.addEventListener("message", function (event) {
// XML file retrieved
if (event.data.sResponseText) {
parser = new DOMParser();
xmlDoc = parser.parseFromString(event.data.sResponseText, "text/xml");
onAfterLoadLevel(xmlDoc);
}
});
As an aside, the mix of colors on that whatwg page would trigger ADD in anybody that didn't already have it. The other reference pages were useless. There were a number of discussions about this issue but nobody has posted the code so I figured I'd do it here.