We have enabled Bot Framework app in our corporate Teams and we want to use AdaptiveCards to present rich content to users. For example, we are sending AdaptiveImage containing url pointing to corporate image store.
Sample code:
new AdaptiveImage
{
Size = AdaptiveImageSize.Small,
Url = new Uri("https://corporate-storage.com/images/image1.png"), // This is image not hosted publicly.
AltText = "Some text"
}
This works fine in WebChat client as the url is just appended to the src attribute of the img HTML tag. However in MS Teams it seems that it is preprocessed by some weird proxy / MITM and the url results in:
https://urlp.asm.skype.com/v1/url/content?url=https%3a%2f%2fcorporate-proxy.com%2fimages%2fimage1.png
When we try to browse the url to see where why the picure is not rendered we see empty page with 502 response code in debugger.
Is there a way how to force MS Teams to not alter src attributes of pictures.
For rendering image in adaptive card, it has to be hosted in public content-delivery network (CDN). Here the official document link.
It worked in WebChat client because in browser your authentication is already cached where as in Teams App there is no cache and the image requires authentication.
You need to host the image in public domain or Azure Blob storage to make it work.
I also have not found a way to resolve that, some gays also ask about this problem.
So, I use tampermonkey to load a JS code piece like this.
// ==UserScript==
// #name New Userscript
// #namespace http://tampermonkey.net/
// #version 0.1
// #description try to take over the world!
// #author You
// #match https://teams.microsoft.com/*
// #icon https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// #grant none
// ==/UserScript==
(function() {
'use strict';
setInterval(function(){
$('img').each(function(){
if($(this).attr('src').startsWith("https://urlp.asm.skype.com/v1/url/content?url=https%3a%2f%2fp.datadoghq.com")){
let datadogUrl=$(this).attr('src').replace("https://urlp.asm.skype.com/v1/url/content?url=","")
datadogUrl=decodeURIComponent(datadogUrl)
$(this).attr('src', datadogUrl);
}
})
}, 5000);
})();
And use Teams Web, not Teams App.
Related
I have published a reactjs website that relies on AJAX requests (POST requests on a graphQL API if that's relevant) to display data.
Using google console fetch & render service, I can see that only my components that do not have to call any API are rendered. Any AJAX based component is not rendered at all.
Google fetch & render does show me 2 rendering pictures of my website (google vs visitor), but both are missing AJAX content.
Is server rendering mandatory in this case ?
I do not have a robots.txt file.
I'm doing something like:
import React, { Component } from 'react';
import { observer } from 'mobx-react';
import { observable, runInAction } from 'mobx';
import axios from 'axios';
import ContributorList from '~/components/global/ContributorList';
import type { User } from '~/types';
import CSSModules from 'react-css-modules';
import styles from './style.less';
#observer
#CSSModules(styles)
export default class Footer extends Component {
#observable contributors: Array<User> = [];
async loadContributors () {
const { data: {
data: data
} } = await axios.post('/', {
query: `
{
users {
id,
name,
slug,
avatar {
secure_url
}
}
}
`
});
runInAction( () => {
this.contributors = data.users;
});
}
componentDidMount () {
this.loadContributors();
}
render () {
return (
<div styleName='contributors'>
{ 'Static content' }
<ContributorList
contributors={ this.contributors }
/>
</div>
);
}
};
In my browser, I can see everything fine ('Static content' + contributors that rare fetched asynchronously). But with google fetch and render, I see 2 screenshots with only 'Static content' displayed.
As a result, my dynamic content does not appear in google search results.
Now all the people are talking about progressive web apps (PWA) which rely on Ajax and rendering the content of the website using client side techniques.
But these techniques are not SEO friendly at all, since Google can't index the classic Ajax request and most of the modern requests.
Since you are using ReactJs, and you want Google to index your website you have to use server side rendering.
This will slow down your website and at the same time Google can crawl and index all your pages, also the user can view it on any device, even the old devices.
When you want to build a PWA or modern web app in general, you have to go back to the basics, for an old technique called graceful degration, which mean if you disabled the JS from your browser still you can see the content and all the functions on your website are work.
This is the same way Google crawl and index your website.
There are many recommendations from Google regarding crawling Ajax content:
Use clean URL structure and avoid using JS links(javascript:void(0);)
Load all the using server side rendering
Make sure that your website is working on all devices(responsive)
Submit XML sitemap
Use canonical links in if you have more than one URL structure (which is not recommended)
We are working on a new project similar to yours, built using reactjs and it will be one of the first PWAs in the world that Google can crawl it like any other website by doing the above points.
Also Google have published an article on their webmaster blog talking about the PWA and any modern web app like yours.
For more details check this link
https://webmasters.googleblog.com/2016/11/building-indexable-progressive-web-apps.html
Regarding the robots.txt file, its recommended to add robots for any website even if you don't have pages to block, but you may want to block the ajax requests and other annoying crawlers.
If I wanted to publish a Google Sheets spreadsheet so I could embed it on a page within an iframe, I would manually do the following:
Navigate to Google Drive
Open a spreadsheet
File > Publish To Web > Embed > Copy the generated iframe link into an html file
How would I programmatically achieve the above through the Google Sheets API using JavaScript on the front end? I'm generating spreadsheets on the fly in my application and want to immediately embed them on the page once created.
Once the sheet is created, I can dynamically create an iframe element with the necessary attributes (the sheets ID, among others). That throws an error. From this question, it looks like a sheet needs to have a published: true attribute or something, but that requires using the Drive API - I'm trying to avoid that. Is this possible to handle only through the Sheets API?
After searching through the entire Sheets API, googling, and just general soul-searching, I had no choice but to include the Drive API and use it to do my bidding. Here's the solution I came up with. Hope this helps someone else out there!
Used this script from Google for the client-side JS library in the index.html file:
<body>
...
<script type="text/javascript" src="https://apis.google.com/js/client.js"></script>
</body>
Then for the JS stuff:
// Cache the api's into variables.
var sheets = gapi.client.sheets;
var drive = gapi.client.drive;
// 1. CREATE NEW SPREADSHEET
sheets.spreadsheets.create({
properties: {
title: 'new-sheet'
}
}).then(function(newSpreadSheet) {
var id = newSpreadSheet.result.spreadsheetId;
// 2. PUBLISH SPREADSHEAT VIA DRIVE API
drive.revisions.update({
fileId: id,
revisionId: 1
}, {
published: true, // <-- This is where the magic happens!
publishAuto: true
}).then(function() {
// 3. DISPLAY SPREADSHEET ON PAGE VIA IFRAME
var iframe = [
'<iframe ',
'src="https://docs.google.com/spreadsheets/d/',
id,
'/pubhtml?widget=true&headers=false&embedded=true"></iframe>'
].join('');
// We're using jQuery on the page, but you get the idea.
$('#container').html($(iframe));
});
});
As you have concluded, it is not possible through the Sheets API today and is only possible through the Drive API (using the PATCH https://www.googleapis.com/drive/v3/files/fileId/revisions/revisionId request, documented at https://developers.google.com/drive/v3/reference/revisions/update).
Is there an API that allows access to Google's Mobile Friendly Test which can be seen at https://www.google.com/webmasters/tools/mobile-friendly/?
If you can't find one by googling, it probably doesn't exist.
A hacky solution would be to create a process with PhantomJS that inputs the url, submits it, and dirty-checks the dom for results.
PhantomJS is a headless WebKit scriptable with a JavaScript API.
However, if you abuse this, there is a chance that google will blacklist your ip address. Light use should be fine. Also be aware that google can change their dom structure or class names at any time, so don't be surprised if your tool suddenly breaks.
Here is some rough, untested code...
var url = 'https://www.google.com/webmasters/tools/mobile-friendly/';
page.open(url, function (status) {
// set the url
document.querySelector('input.jfk-textinput').value = "http://thesite.com";
document.querySelector('form').submit();
// check for results once in a while
setInterval(function(){
var results = getResults(); // TODO create getResults
if(results){
//TODO save the results
phantom.exit();
}
}, 1000);
});
There is an option in pagespeed api
https://www.googleapis.com/pagespeedonline/v3beta1/mobileReady?url={url}&key={api key}
key can be obtained form google cloud platform.
Acquire a PageSpeed Insights API KEY in https://console.developers.google.com/apis/api/pagespeedonline-json.googleapis.com/overview?project=citric-program-395&hl=pt-br&duration=P30D and create a credentials, follow the google's instructions.
In C# (6.0) and .NET 4.5.2, I did some like this:
(add in your project a reference for Newtonsoft.Json.)
String yourURL = "https://www.google.com.br";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://www.googleapis.com");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync($"/pagespeedonline/v3beta1/mobileReady?url={yourURL }&key=AIzaSyArsacdp79HPFfRZRvXaiLEjCD1LtDm3ww").Result;
string json = response.Content.ReadAsStringAsync().Result;
JObject obj = JObject.Parse(json);
bool isMobileFriendly = obj.Value<JObject>("ruleGroups").Value<JObject>("USABILITY").Value<bool>("pass");
There is an API (Beta) for the Mobile Friendly-Test. (Release Date: 31.01.2017).
The API test outputs has three statuses:
MOBILE_FRIENDLY_TEST_RESULT_UNSPECIFIED Internal error when running this test. Please try running the test again.
MOBILE_FRIENDLY The page is mobile friendly.
3.NOT_MOBILE_FRIENDLY The page is not mobile friendly.
Here are more informations: https://developers.google.com/webmaster-tools/search-console-api/reference/rest/v1/urlTestingTools.mobileFriendlyTest/run
I'd like to add a calendar entry from my Firefox plugin to the user's Google calendar (with their authorization, of course). Unfortunately, I can't seem to figure out how to authenticate with Gapi within the context of the Firefox SDK.
I tried including the client.js from gapi directly as a module in my source, but this isn't effective, since it can't access the window object. My next attempt was something akin to what I do with jQuery - load it in a content script:
googleClient.js
var tabs = require("sdk/tabs");
var self = require('sdk/self');
function initAuth() {
var worker = tabs.activeTab.attach({
url: 'about:blank',
contentScriptFile: [self.data.url('gapi.js'), self.data.url('authContentScript.js')]
});
}
exports.initAuth = initAuth;
main.js:
var googleClient = require('./googleClient');
I get the following problem:
console.error: foxplugin:
Error opening input stream (invalid filename?)
In the ideal situation, it would open a new window in the browser that allows the user to login to Google (similar to what happens when one requests access to the oauth2 endpoint from within a "real" content script).
I had the same problem so I've made an npm plugin for that. It's called addon-google-oauth2 and works for Google OAuth2 tested with AdSense API. It's really simple, it just calls REST APIs for OAuth2. Steps:
Create an OAuth2 client for native application. No web or Android, just native.
If your addon is using jpm ok, if it uses cfx, please migrate to jpm
Download and save the dependency with npm
npm install addon-google-oauth2 --save
Follow the tutorial on the README.md file. It's easy, just two API calls
refreshToken(options,callback);
getToken();
Insert the HTML and JS file on your data/ directory
Facebook currently has event handlers for facebook events such as like / recommend. But this is available only for xfbml version of the code. Since facebook is no longer supporting fbml / xfbml (http://www.allfacebook.com/facebook-markup-language-support-ends-jan-1-2011-12) how do we listen to events on iframes? You cannot use javascript methods listening to ids onclick and etc, esp for iframes owned by facebook / twitter. Is there any other solution to this?
Thank you but,
Thanks. I am already using the new Javascript SDK. Scroll down for my code, but I am assuming that this works only for the "xfbml" version of code for facebook like button? does the same apply for iframes too? Assumption based on this text on http://developers.facebook.com/docs/reference/plugins/like/:
The XFBML (also available in HTML5-compliant markup) version is more versatile, but requires use of the JavaScript SDK. The XFBML dynamically re-sizes its height according to whether there are profile pictures to display, gives you the ability (through the Javascript library) to listen for like events so that you know in real time when a user clicks the Like button, and it always gives the user the ability to add an optional comment to the like. If users do add a comment, the story published back to Facebook is given more prominence.
window.fbAsyncInit = function() {
FB.init ({
appId : ,// App ID
channelUrl : ,// Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Listen to click event
FB.Event.subscribe('edge.create', function(response) {
// Do something, e.g. track the click on the "Like" button here
$('#someDiv').show();
});
};
// Load the SDK Asynchronously
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
Yes, you can subscribe to events using the new Javascript SDK. See here: https://developers.facebook.com/docs/reference/javascript/ and https://developers.facebook.com/docs/reference/javascript/FB.Event.subscribe/