Tag : google docs

Amazon Zocalo le concurrent de Google Drive pour les entreprises

Amazon a annoncé il y a quelques jours la sortie de Zocalo
qui est un espace de partage, d’édition et de stockage de documents pour les entreprises. En terme de fonctionnalités offertes les utilisateurs de Google Drive et de Google Docs ne seront pas perturbés car avec Zocalo on fait grosso modo ce que l’on peut faire avec Google Drive et Docs.

La différenciation vient surtout du tarif proposé par Amazon pour Zocalo. En effet, Google Drive for Work est commercialisé à 10$ par mois et par utilisateur, Zocalo est quant à lui facturé 5$ par mois et par utilisateur pour 200Gb de données. On reconnait là la stratégie d’agressivité tarifaire d’Amazon. Ce qui est aussi intéressant c’est qu’Amazon vient de faire un sale coup à Dropbox qui utilise partiellement l’infrastructure d’Amazon pour opérer son service…

https://www.youtube.com/watch?v=wbjMrQtoZlU


Utiliser les données de Google Analytics avec Google Docs pour faire un tableau de bord

Je ne sais pas vous mais google analytics peut avoir des limites dans la génération de certains tableaux de bord. Prenons par exemple un site donc le CA n’est pas identifié dans Google Analytics, ce dernier ne pourra pas avoir une vue simple et unique de son trafic et de son chiffre d’affaires.

Si vous utilisez Google Docs voici une solution testée et approuvée pour récupérer les données de votre profil analytics pour les manipuler dans Google Docs.

Premièrement il faut utiliser le template Google Docs de SEOMOZ qui va vous permettre de vous connecter à votre compte GA (Google Analytics). Pour utiliser ce dernier il faut faire « make a copy ». Ensuite vous avez deux possibilités, soit vous utilisez le template et vous construisez votre tableau de bord dedans soit vous avez déjà un tableau de bord et dans ce cas il va falloir ajouter le script de connection (Google Apps Script) : Tools/Script editor/ puis copié/coller de qui suit :

function getGAauthenticationToken(email, password) {

  //Fetches GA authentication token, which can then be used to fetch data with the getGAdata function
//Created by Mikael Thuneberg
    try {
      
        if (typeof email == "undefined") {
            return "Email address missing";
        }
        if (typeof password == "undefined") {
            return "Password missing";
        }
        if (email.length == 0) {
            return "Email address missing";
        }
        if (password.length == 0) {
            return "Password missing";
        }
        password = encodeURIComponent(password);
        var responseStr
        var randnumber = Math.random()*5000;

      Utilities.sleep(randnumber);
      Utilities.sleep(randnumber);

        var response = UrlFetchApp.fetch("https://www.google.com/accounts/ClientLogin", {
            method: "post",
            payload: "accountType=GOOGLE&Email=" + email + "&Passwd=" + password + "&service=analytics&Source=Mikael Thuneberg-GA Google Docs functions-1.0"
        });
        responseStr = response.getContentText();
        responseStr = responseStr.slice(responseStr.search("Auth=") + 5, responseStr.length);
        return responseStr;
    } catch (e) {
        if (e.message.indexOf("CaptchaRequired") != -1) {
            return "Complete CAPTCHA at http://www.google.com/accounts/" + e.message.slice(e.message.indexOf("CaptchaUrl=") + 11, e.message.length);
        } else {
            return "Authentication failed (" + e.message + ")";
        }
    }
}

function getGAaccountData(authToken, dataType, includeHeaders, maxRows, startFromRow) {
//Fetches account data for the authenticated user
//Input authentication token produced by the getGAauthenticationToken function
//If dataType parameter is omitted, the functions fetches a list profiles to which the user has access
//By specifying the dataType parameters as "goals", the functions will fetch a list of goals by profile
//By specifying the dataType parameters as "segments", the functions will fetch a list of advanced segments
//Created by Mikael Thuneberg
  if (typeof authToken == "undefined") {
        return "Authentication token missing";
    }
    dataType = (typeof dataType == "undefined") ? "profiles" : dataType;
    maxRows = (typeof maxRows == "undefined") ? 200 : maxRows;
    maxRows = (typeof maxRows == "string") ? 200 : maxRows;
    startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;
    startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;
    if (authToken.length == 0) {
        return "Authentication token missing";
    }
    if (dataType.length == 0) {
        dataType = "profiles";
    }
    if (authToken.indexOf("Authentication failed") != -1) {
        return "Authentication failed";
    }
    try {
        authToken = authToken.replace(/\n/g, "");
        dataType = dataType.toLowerCase();
        var URL = "https://www.google.com/analytics/feeds/accounts/default?max-results=" + maxRows + "&start-index=" + startFromRow
        var responseStr;
      
        var response = UrlFetchApp.fetch(URL, {
            method: "get",
            headers: {
                "Authorization": "GoogleLogin auth=" + authToken,
                "GData-Version": "2"
            }
        });
        responseStr = response.getContentText();
        var XMLdoc = Xml.parse(responseStr);
        var lapset2;
        var TempArray = [];
        var RowArray = [];
        var HeaderArray = [];
        if (includeHeaders == true) {
            var rivi = 1;
            if (dataType == "segments") {
                HeaderArray[0] = "Segment ID";
                HeaderArray[1] = "Segment Name";
                HeaderArray[2] = "Segment Definition";
            } else {
                HeaderArray[0] = "Account Name";
                HeaderArray[1] = "Profile Title";
                HeaderArray[2] = "Profile Number";
            }
            TempArray[0] = HeaderArray;
        } else {
            var rivi = 0;
        }
        var sar = 0;
        var lapset;
        var dataFound = false;
        if (dataType == "segments") {
            lapset = XMLdoc.getElement().getElements();
            for (i = 0; i < lapset.length; i++) {
                if (lapset[i].getName().getLocalName() == "segment") {
                    sar = 0;
                    RowArray[0] = lapset[i].getAttribute("id").getValue();
                    RowArray[1] = lapset[i].getAttribute("name").getValue();
                    lapset2 = lapset[i].getElements();
                    for (j = 0; j < lapset2.length; j++) {
                        if (lapset2[j].getName().getLocalName() == "definition") {
                            RowArray[2] = lapset2[j].getText();
                        }
                    }
                    TempArray[rivi] = RowArray;
                    RowArray = [];
                    dataFound = true;
                    rivi++;
                    if (rivi == maxRows) {
                        return TempArray;
                    }
                } else {
                    if (lapset[i].getName().getLocalName() == "entry") {
                        break;
                    }
                }
            }
        } else { // datatype = profiles 
            lapset = XMLdoc.getElement().getElements("entry");
            for (i = 0; i < lapset.length; i++) {
                sar = 0;
                lapset2 = lapset[i].getElements();
                for (j = 0; j < lapset2.length; j++) {
                    if (lapset2[j].getName().getLocalName() == "title") {
                        RowArray[1] = " " + lapset2[j].getText();
                        dataFound = true;
                    } else {
                        if (lapset2[j].getName().getLocalName() == "property") {
                            if (lapset2[j].getAttribute("name").getValue() == "ga:accountName") {
                                RowArray[0] = lapset2[j].getAttribute("value").getValue();
                            }
                            if (lapset2[j].getAttribute("name").getValue() == "ga:profileId") {
                                RowArray[2] = lapset2[j].getAttribute("value").getValue();
                                break;
                            }
                        }
                    }
                }
                TempArray[rivi] = RowArray;
                RowArray = [];
                dataFound = true;
                rivi++;
                if (rivi == maxRows) {
                    return TempArray;
                }
            }
        }
        if (dataFound == false) {
            //return "No data found";
        }
        return TempArray;
    } catch (e) {
        return "0";
    }
}

function getGAdata(authToken, profileNumber, metrics, startDate, endDate, filters, dimensions, segment, sort, includeHeaders, maxRows, startFromRow) {
//Fetches data from the GA profile specified, using the authentication token generated by the getGAauthenticationToken function
//For instructions on the parameters, see http://bit.ly/bUYMDs
//Created by Mikael Thuneberg
  try {
        startDate.getYear();
    } catch (e) {
        return "Invalid start date";
    }
    try {
        endDate.getYear();
    } catch (e) {
        return "Invalid end date";
    }
    try {
        if (typeof authToken == "undefined") {
            return "Authentication token missing";
        }
        if (typeof profileNumber == "undefined") {
            return "Profile number missing";
        }
        if (typeof metrics == "undefined") {
            return "Specify at least one metric";
        }
        if (profileNumber != parseInt(profileNumber)) {
            return "Invalid profile number";
        }
        filters = (typeof filters == "undefined") ? "" : filters;
        dimensions = (typeof dimensions == "undefined") ? "" : dimensions;
        segment = (typeof segment == "undefined") ? "" : segment;
        maxRows = (typeof maxRows == "undefined") ? 100 : maxRows;
        maxRows = (typeof maxRows == "string") ? 100 : maxRows;
        startFromRow = (typeof startFromRow == "undefined") ? 1 : startFromRow;
        startFromRow = (typeof startFromRow == "string") ? 1 : startFromRow;
        if (authToken.length == 0) {
            return "Authentication token missing";
        }
        if (profileNumber.length == 0) {
            return "Profile number missing";
        }
        if (metrics.length == 0) {
            return "Specify at least one metric";
        }
        if (authToken.indexOf("Authentication failed") != -1) {
            return "Authentication failed";
        }
        authToken = authToken.replace(/\n/g, "");
        var startDateString
        var endDateString
        var dMonth
        var dDay
        if (startDate.getMonth() + 1 < 10) {
            dMonth = "0" + (startDate.getMonth() + 1);
        } else {
            dMonth = startDate.getMonth() + 1;
        }
        if (startDate.getDate() < 10) {
            dDay = "0" + startDate.getDate();
        } else {
            dDay = startDate.getDate();
        }
        startDateString = startDate.getYear() + "-" + dMonth + "-" + dDay
        if (endDate.getMonth() + 1 < 10) {
            dMonth = "0" + (endDate.getMonth() + 1);
        } else {
            dMonth = endDate.getMonth() + 1;
        }
        if (endDate.getDate() < 10) {
            dDay = "0" + endDate.getDate();
        } else {
            dDay = endDate.getDate();
        }
        endDateString = endDate.getYear() + "-" + dMonth + "-" + dDay
        if (startDateString > endDateString) {
            return "Start date should be before end date";
        }
        var URL = "https://www.google.com/analytics/feeds/data?ids=ga:" + profileNumber + "&start-date=" + startDateString + "&end-date=" + endDateString + "&max-results=" + maxRows + "&start-index=" + startFromRow;
        if (metrics.slice(0, 3) != "ga:") {
            metrics = "ga:" + metrics;
        }
        metrics = metrics.replace(/&/g, "&ga:");
        metrics = metrics.replace(/ga:ga:/g, "ga:");
        metrics = metrics.replace(/&/g, "%2C");
        URL = URL + "&metrics=" + metrics
        if (dimensions.length > 0) {
            if (dimensions.slice(0, 3) != "ga:") {
                dimensions = "ga:" + dimensions;
            }
            dimensions = dimensions.replace(/&/g, "&ga:");
            dimensions = dimensions.replace(/ga:ga:/g, "ga:");
            dimensions = dimensions.replace(/&/g, "%2C");
            URL = URL + "&dimensions=" + dimensions;
        }
        if (filters.length > 0) {
            if (filters.slice(0, 3) != "ga:") {
                filters = "ga:" + filters;
            }
            filters = filters.replace(/,/g, ",ga:");
            filters = filters.replace(/;/g, ";ga:");
            filters = filters.replace(/ga:ga:/g, "ga:");
            filters = encodeURIComponent(filters);
            URL = URL + "&filters=" + filters;
        }
        if (typeof(segment) == "number") {
            segment = "gaid::" + segment;
        }
        if (segment.length > 0) {
            if (segment.indexOf("gaid::") == -1 && segment.indexOf("dynamic::") == -1) {
                if (segment.slice(0, 3) != "ga:") {
                    segment = "ga:" + segment;
                }
                segment = "dynamic::" + segment;
            }
            segment = encodeURIComponent(segment);
            URL = URL + "&segment=" + segment;
        }
        if (sort == true) {
            URL = URL + "&sort=-" + metrics;
        }
    }
    catch (e) {
        return "0";
    }
    try {
        var response = UrlFetchApp.fetch(URL, {
            method: "get",
            headers: {
                "Authorization": "GoogleLogin auth=" + authToken,
                "GData-Version": "2"
            }
        });
    } catch (e) {
        if (e.message.indexOf("Timeout") != -1) {
            response = UrlFetchApp.fetch(URL, {
                method: "get",
                headers: {
                    "Authorization": "GoogleLogin auth=" + authToken,
                    "GData-Version": "2"
                }
            });
        } else {
            return "0";
        }
    }
    try {
        var responseStr = response.getContentText();
        var XMLdoc = Xml.parse(responseStr);
        var lapset = XMLdoc.getElement().getElements("entry");
        var lapset2;
        var TempArray = [];
        var RowArray = [];
        var HeaderArray = [];
        if (includeHeaders == true) {
            var rivi = 1;
        } else {
            var rivi = 0;
        }
        var sar = 0;
        var dataFound = false;
        for (i = 0; i < lapset.length; i++) {
            sar = 0;
            lapset2 = lapset[i].getElements();
            for (j = 0; j < lapset2.length; j++) {
                if (lapset2[j].getName().getLocalName() == "dimension") {
                    RowArray[sar] = lapset2[j].getAttribute("value").getValue();
                    if (rivi == 1) {
                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();
                    }
                    sar++;
                }
                if (lapset2[j].getName().getLocalName() == "metric") {
                    RowArray[sar] = Number(lapset2[j].getAttribute("value").getValue());
                    if (rivi == 1) {
                        HeaderArray[sar] = lapset2[j].getAttribute("name").getValue();
                    }
                    sar++;
                }
            }
            TempArray[rivi] = RowArray;
            RowArray = [];
            dataFound = true;
            rivi++;
        }
        if (dataFound == false) {
            //return "No data found";
        }
        if (includeHeaders == true) {
            TempArray[0] = HeaderArray;
        }
        return TempArray;
    } catch (e) {
        return "0";
    }

}

J’ai volontairement modifié les messages d’erreurs pour afficher des « 0 » afin de pouvoir tout de même faire des graphiques (même avec des erreurs de connection).

Pour vous connecter vous avez besoin de votre email de compte GA, de votre mot de passe (vous pouvez en faire un spécifique pour cet outil c’est un peu plus secure il me semble) et du profil GA pour lequel vous souhaitez avoir les données. Cet id de profil se trouve dans l’url de votre compte GA soit après « id » pour l’ancienne version de GA ou après le « p » pour la nouvelle interface.

Voilà donc pour la partie connection à GA et script à intégrer. Ensuite il faut copier/coller la page du template de SEOMOZ ou alors se faire sa propre page de récupération de données ce qui est finalement assez simple en utilisant les formules du template. De mon côté ce qui m’intéressait c’était d’avoir des données quotidiennes et non mensuelles, j’ai donc modifié la formule en conséquence.

Attention lors de la récupération des données si vous demandez beaucoup d’information GA va vous retourner des erreurs de connection (des « 0 » avec mon script modifié), il faut donc y aller doucement, je dirai que 30 données à chaque fois c’est un max. Il suffit de faire copié/collé sur 30 cellules.

Et voilà le travail (données issues d’un autre site que 2803.fr), on retrouve des données en provenance de GA et d’autres données comme le total sur ce graphique :

Plus d’information ici et .


Nouveau look pour Google Docs et Spreadsheet

Peu à peu Google déploie sa nouvelle identité visuelle avec une dominance de blanc et de noir comme on a pu le découvrir sur Google+. Aujourd’hui c’est au tour de Google Docs de subir ce lifting très élégant et sobre. Google Spreadsheet et Google Docs sont donc maintenant dans la même charte que le reste des produits Google.


Google ajoute les tableaux croisés dynamiques dans Google Docs

Voici une fonctionnalité qui manquait vraiment à Google Spreadsheets l’excel de Google Docs. Et au vue de la vidéo de présentation l’utilisation de pivot table dans Google Docs semble bien plus évidente que dans un Excel! Plus le temps passe et moins je me dis que je vais racheter la suite office…

Couplé avec Google Form (l’outil de questionnaires et sondages), le traitement des données va être facilité. Je pense que Google va même y ajouter des fonctionnalités de traitement adaptées… Vivement ces outils que l’on puisse abandonner les sphinx and co!


Google vient enfin de signer l’arrêt de mort d’IE6

Enfin, voici une nouvelle attendue depuis bien longtemps par tous ceux qui développent des sites internet et dont les clients les tannaient pour des compatibilités avec le vieux Internet Explorer 6 qui faisait étonnamment de la résistance dans de très grandes entreprises (j’ai des noms et vous aussi je pense). Bref, Google par le biais d’un email a annoncé que certains de ses services Google Apps (Google Docs suite et the Google Sites editor) ne seraient plus compatibles avec IE6 à partir du 1er mars 2010. Google annonce aussi que plus tard dans l’année Gmail et Google Calendar ne seront eux aussi plus compatibles… Une bien bonne nouvelle!

Ci-dessous une copie de l’email reçu, je vais le garder c’est un collector…

Dear Google Apps admin,​

In order to continue to improve our products and deliver more sophisticated features and performance, we are harnessing some of the latest improvements in web browser technology. This includes faster JavaScript processing and new standards like HTML5. As a result, over the course of 2010, we will be phasing out support for Microsoft Internet Explorer 6.0 as well as other older browsers that are not supported by their own manufacturers.

We plan to begin phasing out support of these older browsers on the Google Docs suite and the Google Sites editor on March 1, 2010. After that point, certain functionality within these applications may have higher latency and may not work correctly in these older browsers. Later in 2010, we will start to phase out support for these browsers for Google Mail and Google Calendar.

Google Apps will continue to support Internet Explorer 7.0 and above, Firefox 3.0 and above, Google Chrome 4.0 and above, and Safari 3.0 and above.

Starting this week, users on these older browsers will see a message in Google Docs and the Google Sites editor explaining this change and asking them to upgrade their browser. We will also alert you again closer to March 1 to remind you of this change.

In 2009, the Google Apps team delivered more than 100 improvements to enhance your product experience. We are aiming to beat that in 2010 and continue to deliver the best and most innovative collaboration products for businesses.

Thank you for your continued support!

Sincerely,

The Google Apps team

Merci le HTML5


Google propose aussi du stockage en ligne de fichiers

Je suis étonné qu’il ait fallu attendre aussi longtemps pour que Google propose ce type de service… Il y a bien longtemps il y avait même des plugins (Google Drive) pour virtuellement utiliser l’espace de stockage de gmail pour y poser des fichiers. Bref le 12 janvier, Google a annoncé qu’ils allaient proposer dans quelques semaines un espace de stockage de 1 giga, le tout gratuitement bien entendu, et avec la possibilité d’acheter de la capacité complémentaire à un prix défiant toute concurrence : 0,25$/an le giga supplémentaire.

L'interface actuelle d'upload de fichiers

Ce qui est intéressant avec cette offre c’est que vous allez réellement stocker vos fichiers, qu’ils soient compatibles ou non avec l’offre Google Docs (donc des zip, des pdf…). La seule limite c’est que le document ne devra pas faire plus de 250mb, ce qui reste rare avec un fichier word mais ce qui vous empèchera de stocker vos films de vacances… Bien entendu ces fichiers seront accessibles dans un mode collaboratif, Google vient encore de plomber un business (adieu drop.io, et tout les autres services permettant d’envoyer de très gros fichiers pour dépasser les limites d’envoi des messageries…).

Et cerise sur le gâteau, ce service fonctionnera aussi avec Google Apps, l’offre business de Google.


Google Docs de plus en plus proche des étudiants

Google avec sa suite logicielle en ligne doit commencer à faire un peu d’ombre à Microsoft car de nos jours les étudiants (pas encore les lycéens) disposent de connexions continues à Internet facilitant l’usage des solutions Saas (Software as a service) comme Google Docs. Pour faciliter l’usage de cette suite logicielle Google adapte l’outil au besoin de cette cible très stratégique (n’oubliez pas que les étudiants sont les travailleurs et décideurs de demain).

Parmi les nouveautés, Google Docs intègre un système d’édition d’équations, la possibilité d’écrire des équations chimiques ou algébriques (souvent pas facile à écrire sur un ordinateur), et un Enorme système de traduction en ligne qui permet de traduire des mots ou bien des documents en entier!

google-docs-equation

Une stratégie qui paiera sur le long terme c’est certain. En tout cas l’aspect collaboratif est bien mis en scène dans cette vidéo :