Building a Google Apps Script Web App, Part 1


Intro



Google Apps Script is a powerful development platform that let you execute custom code in Google’s infrastructure. It main strengths are the tight integration with Google Apps services, the built-in security features and the straightforward developer environment and one click deployment. It started as a scripting tool for spreadsheets similar to macros but with the most recent additions it has become a full fledge Platform as a Service (PaaS).

Many of the enterprise applications tend to be very form centric doing CRUD operations most of the time, I figured it would be interesting to have the Apps Script version of the Django framework reference tutorial: the Polls web app. Doing this will help us understand how to write a complete Web application from the UI to the database.

The poll app is very very simple, it’s like a CRUD hello world. The domain model is made of a Poll class (a question) which have associated many Choices (or possible answers for the poll’s question), the user is presented with the available polls list when he click in one of them is redirected to the poll detail with the different choices as options, the users vote for the best choice and finally the results are presented, number of votes for each one of the choices.

Libraries and Versions

It is a good software practice in general to clearly separate concerns and responsibilities in different layers and in different modules, each one specializes in a certain function. It also helps the maintainability of the code when the application becomes bigger and more complex. Apps script applications are no different, but until recently you had to pack all your code in one big file, with the introduction of libraries you can reuse your code by modularizing it in different libraries (similar to JAR files in Java). Each library will have a version, so the library developer can release many different updates without breaking others code.

We’ll start the tutorial by defining the project layout in the following figure, where we will keep separate the presentation (views and templates) from the business logic (model and services) from the persistence, which in our case will be powered by the built-in ScriptDB JSON database.



It’s very easy to save a project as a library and also import it in another project. First you have to save a version of the  project going to “File” -> “Manage Versions” then go to “File” -> “Project properties...” and copy the project key, a string that serve as the unique identifier for every apps script project. In the other project, go to “Resources” -> “Manage Libraries” and paste the previously copied key, you can select the right version and assign a string identifier which will be the one you use to invoke the library methods (you’ll see in the next section).

For now, let’s define our data model, as you can guess is very simple:

models.gs

function Poll(question, pubDate) {
 // text of the question
 this.question = question;
 // date/time of publishing
 this.pubDate = pubDate.getTime();
 this.type = 'poll';
}
function Choice(pollId, choice, votes) {
 // string generated unique id of the poll
 this.pollId = pollId;
 // text of the choice
 this.choice = choice;
 // integer number of votes
 this.votes = votes;
 this.type = 'choice';
}

ScriptDB

ScriptDB is a JSON objects database that supply all the efficient storage and query needs for our Apps Script app. Note that there is a field “type” in both entities of the models, that’s because ScriptDB will persist JSON objects without having the notion of type, table nor class, in other words, there is no enforced schema here. Querying, Inserting, updating and deleting are done with the ScriptDBInstance API. Query are done “by example” that means by giving an object filled with the query criteria.

As our project structure diagram shows, all the interaction with ScriptDB will be done by the service component, which will provide an API for retrieving and manipulating the data model objects.

services.gs

/**
* Get all the available polls
*
* @return {Result} the result set that contains the poll objects
*/
function getPolls() {
 var db = ScriptDb.getMyDb();
 return db.query({type: 'poll'});
}

/**
* Get the poll object for the given poll id
*
* @param {string} string unique id of the poll
* @return {Poll} the stored poll object
*/
function getPollById(pollId) {
 var db = ScriptDb.getMyDb();
 return db.load(pollId);
}

/**
* Get the choices associated with the given poll id
*
* @param {string} string unique id of the poll
* @return {Result} the result set that contains the choice objects
*/
function getPollChoices(pollId) {
 var db = ScriptDb.getMyDb();
 return db.query({type: 'choice', pollId: pollId});
}

/**
* Given the choice id retrieves the object from the DB and increment by one the vote attribute, finally saves
*
* @param {string} string unique id of the choice
*/
function recordVote(choiceId) {
 var db = ScriptDb.getMyDb();
 var choice = db.load(choiceId);
 choice.votes++;
 db.save(choice);
}
HTMLService
So we have the data model, and the services layer to make operations using the data model, but how do we display this to the user? HTMLService provide a way to render HTML by merging templates with data generated by scripts. There are two important methods in the view, doGet and doPost they are the initial point depending on the HTTP action that we are trying to make, since in our app we have only been assigned with one and only one URL path for the whole application, we need to make use of a special parameters to route and dispatch the view function to use.  

views.gs

function doGet(e) {
 Logger.log('Polls application reached, accessing with parameters = ' + e.queryString);
 var evaluated = undefined;
 if(!e.parameter || !e.parameter.view || e.parameter.view == 'index'){
   Logger.log('Either no parameters, no view param or view equals index');
   evaluated = getIndex();
 } else if(e.parameter.view == 'detail'){  
   evaluated = getDetail(e.parameter.poll);
 } else if(e.parameter.view == 'results'){
   evaluated = getResults(e.parameter.poll);
 } else {
   Logger.log('Error, undefined view');
   evaluated = undefined;
   throw new Error('Error, undefined view');
 }
 return evaluated;
}

function doPost(e) {
 Logger.log('Polls form submitted with vote for [' + e.parameter.choice + '] in poll [' + e.parameter.pollId + ']');
 PollService.recordVote(e.parameter.choice);
 return getResults(e.parameter.pollId);
}

function getIndex(){
 Logger.log('Index view: returning all available polls.');
 var t = HtmlService.createTemplateFromFile('index');
 t.polls = PollService.getPolls();
 t.serviceUrl = getServiceUrl();
 return t.evaluate();
}

function getDetail(pollId){
 Logger.log('Detail view: returning poll with id = ' + pollId);
 var t = HtmlService.createTemplateFromFile('detail');
 t.serviceUrl = getServiceUrl();
 t.poll = PollService.getPollById(pollId);
 t.choices = PollService.getPollChoices(pollId);
 return t.evaluate();
}

function getResults(pollId){
 Logger.log('Results view: returning poll');
 var t = HtmlService.createTemplateFromFile('results');
 t.serviceUrl = getServiceUrl();
 t.poll = PollService.getPollById(pollId);
 t.choices = PollService.getPollChoices(pollId);
 return t.evaluate();
}

index.html

<html>
 <? if (polls.getSize() > 0) { ?>
 <h1>Polls</h1>
 <ul>
   <? while (polls.hasNext()) {
  var poll = polls.next(); ?>
<li><a href="<?= serviceUrl ?>/?view=detail&poll=<?= poll.getId() ?>"><?= poll.question ?></a></li>
   <? } ?>  
 </ul>  
 <? } else { ?>
 <p>No polls are available.</p>
 <? } ?>
</html>

detail.html

<html>
 <h1><?= poll.question ?></h1>
 <form action="<?= serviceUrl ?>" method="post">
 <label>Choices:</label>
 <ul>
  <? while (choices.hasNext()) {
  var choice = choices.next(); ?>
  <li><label><input type="radio" value="<?= choice.getId() ?>" name="choice" /> <?= choice.choice ?></label></li>
   <? } ?>  
 </ul>
 <input type="hidden" value="<?= poll.getId() ?>" name="pollId" />  
 <input type="submit" value="Vote"/>
 </form>
 
 <a href="<?= serviceUrl ?>/?view=index">Back to poll list</a>
</html>  

results.html

<html>
 <h1><?= poll.question ?></h1>
 <ul>
 <? while (choices.hasNext()) {
  var choice = choices.next(); ?>
 <li><?= choice.choice ?> -- <?= choice.votes ?> votes</li>
 <? } ?>
 </ul>
 
 <a href="<?= serviceUrl ?>/?view=detail&poll=<?= poll.getId() ?>">Vote again?</a><br/>
 <a href="<?= serviceUrl ?>/?view=index">Back to poll list</a>
</html>

Deployment and Script Properties

Deployment in this platform is dead simple. First we have to publish a version of the views project (as we did with the library) and then click on “Publish” -> “Deploy as webapp...” this will ask you who will have access to the published app and who will the script be running as. Copy the generated URL and create a new script property “File” -> “Project Properties”-> “Script Properties” called serviceUrl, paste the URL as the value. In our code we need to pass this URL as a variable in each one of the views so add the constant and the getServiceUrl helper method to the views file.

views.gs

/**
* Key of ScriptProperties for saving the app URL.
* @type {String}
* @const
*/
var SERVICE_URL_PROPERTY_NAME = "serviceUrl";

/**
* @return String URL where this script is published as a service.
*/
function getServiceUrl() {
 var url = ScriptProperties.getProperty(SERVICE_URL_PROPERTY_NAME);
 if (url == null) {
   url = "";
 }
 return url;
}
Deploy again and our app is ready for taking some votes.

If you want to see the source code it is published in two separate AppsScript projects: 



Findings and Next Steps

Even though we have all the components and successfully built this simple but fully functional webapp, there is a need for a more comprehensive application framework, that takes care of MVC concepts, URL handling and dispatching,  forms generation and validation, etc. If you have previously used Zend, or Spring or Django you’ll know what I mean.

Our app is clearly not complete at all, we’ve just made the user interactions but there should be an admin interface for managing the polls and the choices, that means we should have an ACL where only certain users (e.g admins) have permissions to do only certain actions. We could also record who made the voting when, in case of latter auditing needs. In the graphic design side our app is very raw, we could add some styles and graphics.

References




Development Manager
Eforcers S.A.


Una solución a sus casos


Queremos presentarle una opción que ayudará a solucionar casos en su empresa en el momento que requiera soporte por algún motivo, he aquí un ejemplo de ello.

Existen actualmente dos inconvenientes que pueden resultar complejos con Google+ en las cuentas de nuestros clientes, le brindamos la solución que podría resultar efectiva para estos inconvenientes:

Cuando se inicia la aplicación por primera vez, Google +, solicita la fecha de nacimiento y los datos personales del usuario.

Causa: Registro de fecha de nacimiento menor a 12 años. (Google Apps bloquea la cuenta por políticas de Google +, sobre el uso de la aplicación por menores de edad).
Problema: Compartimos la respuesta que siempre damos sobre este caso.

Respondiendo a su solicitud y de acuerdo a nuestro compromiso, los pasos a realizar para desbloquear una cuenta de correo que ha sido bloqueada por límite de edad son:

1. Ingrese a www.google.com/accounts e ingrese usuario@dominio.com y su clave como se muestra en la siguiente imagen



2. Haga clic sobre el enlace "Star a new request" como se muestra en la siguiente imagen


3. Ingrese su fecha de nacimiento real y luego clic en el enlace Send a form online


4. El usuario debe escanear la cédula por los dos lados y adjuntarla en uno de los formatos que indica el sistema y por último presionar el botón I Agree

El desbloqueo de la cuenta puede tardar hasta 24 horas.

Para más información le sugerimos visitar el siguiente enlace: http://www.google.com/support/accounts/bin/answer.py?hl=es&answer=1333913


Revoluciona Google Plus más que una Red Social


Además de la gran cantidad de aplicaciones que maneja Google Apps con su exclusividad para las empresas, Google también tiene su propia herramienta comunicativa en la Web, llamada Google+. 
Es por ello que para conocer más a fondo sobre las principales ventajas en el ámbito empresarial, hemos entrevistado a una experta en el tema Diana Cifuentes de Eforcers, quién nos habla sobre la percepción que se puede llegar a tener sobre este medio.

Entrevistador:¿En qué beneficia Google+ a una empresa?
Diana: Facilita la comunicación entre las personas de la empresa a través de Hangouts o Posts compartiendo información de una forma más simple.

Entrevistador: Teniendo en cuenta que existen diversas redes sociales ¿En qué se diferencia de las demás?
Diana: 1. Google+ introduce una nueva figura de círculos para compartir información segmentada, por ejemplo lo único que quieres compartir con tus compañeros de trabajo o clientes.
2. Los Hangouts que puedes realizar con los compañeros u otras personas que se encuentren en cualquier lugar. 
3. Tiene muchas más utilidades y beneficios para las empresas compartiendo información empresarial y crear eventos internos.

Entrevistador: Muchas veces se puede llegar a pensar que dentro del ambiente laboral, tener otras aplicaciones diversas pueden causar pérdida de atención y disminuir la productividad de las actividades diarias ¿Por qué Google+ no es un distractor de tiempo?
Diana: Muchas de las herramientas que se tienen en una empresa son distractores si no se usan adecuadamente en parte mucho de éste trabajo se hace a través de políticas corporativas, sin embargo se puede restringir su uso a personas que realmente puedan usarlo de la manera incorrecta.

Entrevistador: Desde su punto de vista ¿Google+ tiene alguna desventaja?
Diana: Que todavía no está cerrado para el ambiente corporativo, sería ideal que en un futuro cercano se pudiera cerrar el uso de Google+ solo a nivel intradominio, con esto poder estar mucho más seguros que la información que se comparte allí es solo para uso empresarial.

Teniendo en cuenta lo anterior, Google+ maneja muchas posibilidades, que dentro de su empresa podrían funcionar para facilitar aspectos de comunicación interna, además de proporcionar beneficios como el acceso en cualquier momento y compartir información verdaderamente de su interés laboral. 

Imagen: 

Google Apps: Una experiencia de enseñanza organizacional.

Las compañías cuentan con recursos similares en cuanto a recursos materiales de los cuales hace uso para competir en el mercado, pero ¿cuáles son los recursos de los que puede disponer una compañía para marcar la diferencia? Muchos especialistas en la materia sostienen que la ventaja competitiva se encuentra en el conocimiento.

Se puede entender el concepto de conocimiento como “la percepción y entendimiento de un mensaje por parte de un individuo con relación al objeto”.

Las compañías no pueden crear por sí solas el conocimiento, son las personas que componen la compañía quienes crean y establecen las nuevas ideas, pensamientos y experiencias que proponen el conocimiento de la compañía.

Google Apps presenta una gran ventaja para las compañías al momento de condensar y replicar éste conocimiento creado por y para el personal de la organización, ya que posee herramientas que potencializan el flujo del conocimiento entre los diferentes usuarios.
Por ejemplo una forma de potencializar éste conocimiento puede ser a través de los sites de Google, los cuales ayudan a compartir la información necesaria para difundir el conocimiento, la forma en que se organizan los sites permite que los usuarios suban vídeos, calendarios, documentos y presentaciones disponibles para todos los visitantes del sitio.

Las facilidades que proporciona Google Docs, empezando por la capacidad de compartir documentos a múltiples usuarios y que estos trabajen sobre éste al mismo tiempo, potencializa la colaboración entre usuarios. Además de la posibilidad de crear formularios, ya que éstos otorgan la posibilidad de realizar encuestas y/o evaluaciones cuyos resultados son perfectamente cuantificables y disponibles para análisis. ¡Todo dentro de una misma herramienta!

Por ejemplo un tutor puede crear un sitio donde comparta información exclusiva para un Grupo, solicitar trabajos por este medio sin necesidad de recibirlos de forma física, puede revisar quién realizó modificaciones y quién colaboró, revisando el Historial de Cambio, además de tener control total sobre la información que allí comparte.

Otra de las posibilidades que ofrece Google Apps se encuentra por medio de Google Grupos, donde es posible desarrollar actividades relacionadas con proceso de aprendizaje activo como lo son los Foros, en los que usted puede compartir información exclusiva, restringir los miembros del grupo por medio de la lista de correos y asignar permisos entre otros aspectos que ayudarán para la enseñanza o formación de su organización.

Google presenta muchas opciones que usted puede poner a su disposición y en práctica para el desarrollo de procesos educativos dentro de su compañía, los cuales le ayudarán a potencializar el conocimiento y los procesos de mejora continua para alcanzar mejores índicadores de calidad y productividad de sus colaboradores dentro de su empresa.

Fuente: Gestión del Cambio Docente Carlos Alberto Rico, Abril 2011
http://courses.skola.edu.mt/wp-content/uploads/2009/01/elearning.jpg

Eforcers Te Invita a Participar en el Google Apps Developer Challenge 2012


Qué es?

El Google Apps Developer Challenge 2012 es un concurso para desarrolladores que está organizando el equipo de mercados emergente de Google. El propósito del concurso es incentivar el uso de tecnologías Google en proyectos de desarrollo de aplicaciones de software, específicamente con Google Apps Script, Google Drive y los APIs de Google Apps. Hay tres categorías de soluciones:


  • Para empresas (PyMes o grandes) por ejemplos aplicaciones de contabilidad, ventas, flujos de trabajo, colaboración
  • Para consumidores, por ejemplo social, productividad personal, juegos y diversión
  • Para entidades educativas, sin ánimo de lucro, salud

Van a haber premios interesantes en dinero para los ganadores de cada región geográfica y premios adicionales para finalistas cuyos equipos estén compuestos por estudiantes o por mujeres. Ojo! la fecha límite de envío de aplicaciones es el próximo 24 de Agosto de 2012.

Por qué participar?

Google Apps cada día más se perfila como la solución empresarial para comunicación y colaboración “ por de facto”, ya que más de 5’000.000 de empresas alrededor de todo el mundo usan a diario sus aplicaciones para ser más eficientes y competitivas. Google Apps trae a las empresas consigo una nueva forma de trabajar, donde lo único que se necesita para sacarle provecho es el navegador y una conexión a Internet.

Sin embargo, Google Apps como tal no cubre el 100% de las necesidades tecnológicas ni de negocio de las empresas pero sí ofrece herramientas para integrarse o extenderse (APIs) o para aprovechar su infraestructura (Google App Engine, Google Apps Script). Los proveedores de software juegan un rol muy importante en este ecosistema tanto para Google para complementar y robustecer su suite como para sus productos para entrar a generar valor a sus clientes a una escala global.

Cómo Eforcers te puede ayudar si decides participar?


A diario recibimos en Eforcers solicitudes, tanto de nuestros clientes como de prospectos, acerca de necesidades específicas de tecnologías o del negocio que podrían hacer su labor más productiva y sobre todo más fácil. En otros casos, al convertirnos en aliados de nuestros clientes, observamos directamente procesos que se podrían optimizar y hacer más eficientes si se aprovecharan las herramientas que Google pone a nuestra disposición. En muchos casos y desde el inicio de esta línea de negocio, hemos desarrollado soluciones alrededor de dichas herramientas, lo cual nos ha dado bastante experiencia en decidir que APIs y plataformas aplican o no para determinado problema. 


No obstante contamos con recursos limitados o en otros casos no tenemos el conocimiento especializado específico del negocio para desarrollar la solución. Como distribuidor autorizado de Google, nos conviene que aumente la cantidad y calidad de desarrolladores que ya cuenten con este conocimiento y ofrezcan soluciones innovadoras, así que estaremos dispuestos a guiar con toda la asesoría, el consejo y las recomendaciones que sean necesarias a partir de todo lo que hemos vivido para que las aplicaciones sean más relevantes y más importante aún, que generen mayor valor a nuestros clientes.


Parte de este compromiso va más allá de este concurso, se ha venido haciendo de manera contínua en forma de apoyo al grupo de desarrolladores de Google, GDG Bogotá, donde también se promueve el uso de tecnologías de Google en general.

Más Información









 
Coordinador de desarrollo
Eforcers S.A.