Cómo crear un complemento de Classroom

Esta es la primera explicación de la serie sobre complementos de Classroom.

En esta explicación, sentarás las bases para desarrollar una aplicación web y publicarla como un complemento de Classroom. En los próximos pasos de la explicación, se expande la app.

En esta explicación, completarás lo siguiente:

  • Crea un proyecto de Google Cloud nuevo para tu app web.
  • Crea una app web de esqueleto con botones de acceso con marcadores de posición.
  • Publica una ficha de Play Store privada de Google Workspace Marketplace (GWM) para tu app web.

Cuando termines, puedes instalar el complemento y cargarlo en el iframe de los complementos de Classroom.

Requisitos previos

Elige uno de los siguientes idiomas para ver los requisitos previos correspondientes:

Python

En el ejemplo de Python, se usa el framework de Flask. Puedes descargar el código fuente completo para todas las explicaciones desde la página Descripción general. El código para esta explicación en particular se encuentra en el directorio /flask/01-basic-app/.

Si es necesario, instala Python 3.7+ y asegúrate de que pip esté disponible.

python -m ensurepip --upgrade

También te recomendamos que configures y actives un entorno virtual nuevo de Python.

python3 -m venv .classroom-addon-env
source .classroom-addon-env/bin/activate

Cada subdirectorio de explicación en los ejemplos descargados contiene un requirements.txt. Puedes instalar rápidamente las bibliotecas requeridas con pip. Usa lo siguiente a fin de instalar las bibliotecas necesarias para esta explicación.

cd flask/01-basic-app
pip install -r requirements.txt

Node.js

En nuestro ejemplo de Node.js, se usa el marco de trabajo Express. Puedes descargar el código fuente completo para todas las explicaciones desde la página Descripción general.

Si es necesario, instala NodeJS v16.13+.

Instala los módulos de nodo necesarios con npm.

npm install

Java

En nuestro ejemplo de Java, se usa el framework de Spring Boot. Puedes descargar el código fuente completo para todas las explicaciones desde la página Descripción general.

Instala Java 11+ si aún no lo tienes instalado en tu máquina.

Las aplicaciones de Spring Boot pueden usar Gradle o Maven para controlar compilaciones y administrar dependencias. En este ejemplo, se incluye el wrapper de Maven que garantiza una compilación exitosa sin necesidad de que instales Maven.

Para poder ejecutar el ejemplo proporcionado, ejecuta los siguientes comandos en el directorio en el que descargaste el proyecto y asegúrate de que cuentas con los requisitos previos para ejecutar el proyecto.

java --version
./mvnw --version

O en Windows:

java -version
mvnw.cmd --version

Configura un proyecto de Google Cloud

Los proyectos de Google Cloud controlan el acceso a la API de Classroom y a los métodos de autenticación necesarios. Las siguientes instrucciones te guiarán a través de los pasos mínimos para crear y configurar un proyecto nuevo para usar con tu complemento.

Crea el proyecto

Visita la página de creación de proyectos para crear un proyecto de Google Cloud nuevo. Puedes proporcionarle cualquier nombre al proyecto nuevo. Haz clic en Crear.

El proyecto nuevo tarda unos minutos en crearse por completo. Cuando termines, asegúrate de seleccionar el proyecto, puedes elegirlo en el menú desplegable del selector de proyectos en la parte superior de la pantalla o hacer clic en SELECCIONAR PROYECTO en el menú de notificaciones de la esquina superior derecha.

Selecciona el proyecto
en la consola de Google Cloud

Adjunta el SDK de GWM al proyecto de Google Cloud

Navega al navegador Biblioteca de API. Busca Google Workspace Marketplace SDK. Deberías ver el SDK en la lista de resultados.

La tarjeta del SDK de Google Workspace Marketplace

Selecciona la tarjeta del SDK de Google Workspace Marketplace y, luego, haz clic en Habilitar.

Configura el SDK de GWM

GWM proporciona la lista a través de la cual los usuarios y administradores instalan tu complemento. Configura la pantalla de consentimiento de OAuth y la configuración de la app y la ficha de Play Store del SDK de GWM para continuar.

La pantalla de consentimiento de OAuth aparece cuando los usuarios autorizan tu app por primera vez. Les solicita que permitan que tu app acceda a la información personal y de la cuenta, según lo establecido por los alcances que habilites.

Navega a la página de creación de la pantalla de consentimiento de OAuth. Proporcione la siguiente información:

  • Configura el campo User Type como Externo. Haga clic en Crear.
  • En la página siguiente, completa los detalles de la app y la información de contacto requeridos. Proporciona cualquier dominio que aloje tu app en Dominios autorizados. Haz clic en GUARDAR Y CONTINUAR.
  • Agrega los permisos de OAuth que requiera tu app web. Consulta la Guía de configuración de OAuth para obtener un análisis detallado de los alcances y su propósito.

    Debes solicitar al menos uno de los siguientes permisos para que Google envíe el parámetro de consulta login_hint. Puedes encontrar una explicación más detallada de este comportamiento en nuestra guía de configuración de OAuth:

    • https://www.googleapis.com/auth/userinfo.email (ya incluido)
    • https://www.googleapis.com/auth/userinfo.profile (ya incluido)

    Los siguientes permisos son específicos de los complementos de Classroom:

    • https://www.googleapis.com/auth/classroom.addons.teacher
    • https://www.googleapis.com/auth/classroom.addons.student

    Además, incluye cualquier otro permiso de la API de Google que requiera tu app para los usuarios finales.

    Haz clic en GUARDAR Y CONTINUAR.

  • En la página Usuarios de prueba, enumera las direcciones de correo electrónico de las cuentas de prueba. Haz clic en GUARDAR Y CONTINUAR.

Confirma que tu configuración sea correcta y, luego, regresa al panel.

Configuración de la app

Navega a la página de configuración de la app del SDK de GWM. Proporcione la siguiente información:

  • Establece la Visibilidad de la app en Private. Esta configuración es apropiada para pruebas y desarrollo, y es la opción adecuada para estas explicaciones. Elige Public solo si tienes todo listo para que el público general lo use.

  • Establece la Configuración de instalación en Admin Only install si deseas restringir la instalación a los administradores de dominio.

  • En Integración de apps, selecciona Complemento de Classroom. Se te solicitará el URI de configuración de archivo adjunto seguro, que es la URL que esperas que se cargue cuando un usuario abra tu complemento. A los fines de esta explicación, debería ser https://<your domain>/addon-discovery.

  • Los prefijos de URI de archivo adjunto permitidos se usan para validar los URI configurados en AddOnAttachment con los métodos courses.*.addOnAttachments.create y courses.*.addOnAttachments.patch. La validación es una coincidencia de prefijo de string literal y no permite el uso de comodines en este momento. Por ahora, puedes dejarlas vacías.

  • Agrega los mismos permisos de OAuth que se proporcionan en la pantalla de consentimiento de OAuth en el paso anterior.

  • Completa los campos según corresponda para tu organización en Vínculos para desarrolladores.

Ficha de Play Store

Navega a la página de la ficha de Play Store del SDK de GWM. Proporcione la siguiente información:

  • En Detalles de la app, agrega un idioma o expande el menú desplegable junto al idioma que ya aparece en la lista. Proporciona un nombre de la aplicación y descripciones, que aparecerán en la página de la ficha de Play Store de GWM de tu complemento. Haz clic en Listo para guardar los cambios.
  • Elige una Categoría para tu complemento.
  • En Recursos gráficos, proporciona las imágenes para los campos obligatorios. Se pueden cambiar más adelante y pueden ser marcadores de posición si configuraste la visibilidad de la app como Privada en el paso anterior.
  • En Vínculos de compatibilidad, proporciona las URLs solicitadas. Estos pueden ser marcadores de posición si configuraste la visibilidad de la app como Privada en el paso anterior.

Haz clic en PUBLICAR para guardar tu configuración. Si configuraste la visibilidad de la app como Privada en el paso anterior, la app estará disponible de inmediato para su instalación. Si configuras la visibilidad de la app como Pública, se enviará la app para que la revise el equipo de GWM antes de que esté disponible para la instalación.

Instala el complemento

Ahora puedes instalar tu complemento con el vínculo que se encuentra en la parte superior de la página de la ficha de Play Store del SDK de GWM. Haz clic en URL de la app en la parte superior de la página para ver la lista y, luego, elige Instalar.

Compila una app web básica

Configura una aplicación web de base con dos rutas. En los próximos pasos de la explicación, se expande esta aplicación, por lo que, por ahora, solo crea una página de destino para el complemento /addon-discovery y una página de índice simulada / para el “sitio de la empresa”.

Ejemplo de aplicación web en iframe

Implementa estos dos extremos:

  • /: Muestra un mensaje de bienvenida y un botón para cerrar la pestaña actual y el iframe del complemento.
  • /addon-discovery: Muestra un mensaje de bienvenida y dos botones: uno para cerrar el iframe del complemento y otro para abrir un sitio web en una pestaña nueva.

Ten en cuenta que agregamos botones para crear y cerrar ventanas o el iframe. Estas demuestran un método que permite llevar al usuario a una pestaña nueva de forma segura para obtener autorización en la siguiente explicación.

Crear secuencia de comandos de utilidad

Crea un directorio static/scripts. Crea un archivo nuevo addon-utils.js. Agrega las dos funciones siguientes.

/**
 *   Opens a given destination route in a new window. This function uses
 *   window.open() so as to force window.opener to retain a reference to the
 *   iframe from which it was called.
 *   @param {string} destinationURL The endpoint to open, or "/" if none is
 *   provided.
 */
function openWebsiteInNewTab(destinationURL = '/') {
  window.open(destinationURL, '_blank');
}

/**
 *   Close the iframe by calling postMessage() in the host Classroom page. This
 *   function can be called directly when in a Classroom add-on iframe.
 *
 *   Alternatively, it can be used to close an add-on iframe in another window.
 *   For example, if an add-on iframe in Window 1 opens a link in a new Window 2
 *   using the openWebsiteInNewTab function above, you can call
 *   window.opener.closeAddonIframe() from Window 2 to close the iframe in Window
 *   1.
 */
function closeAddonIframe() {
  window.parent.postMessage({
    type: 'Classroom',
    action: 'closeIframe',
  }, '*');
};

Crea rutas

Implementa los extremos /addon-discovery y /.

Python

Configura el directorio de la aplicación

A los fines de este ejemplo, estructura la lógica de la aplicación como un módulo de Python. Este es el directorio webapp de nuestro ejemplo proporcionado.

Crea un directorio para el módulo de servidor, por ejemplo, webapp. Mueve el directorio static al directorio del módulo. Crea un directorio template en el directorio del módulo también; tus archivos HTML van aquí.

Compila el módulo del servidor*

Crea el archivo __init__.py en el directorio de tu módulo y agrega las siguientes importaciones y declaraciones.

from flask import Flask
import config

app = Flask(__name__)
app.config.from_object(config.Config)

# Load other module script files. This import statement refers to the
# 'routes.py' file described below.
from webapp import routes

Luego, crea un archivo para manejar las rutas de la app web. Es webapp/routes.py en nuestro ejemplo proporcionado. Implementa las dos rutas en este archivo.

from webapp import app
import flask

@app.route("/")
def index():
    return flask.render_template("index.html",
                                message="You've reached the index page.")

@app.route("/classroom-addon")
def classroom_addon():
    return flask.render_template(
        "addon-discovery.html",
        message="You've reached the addon discovery page.")

Ten en cuenta que nuestras rutas pasan una variable message a sus respectivas plantillas de Jinja. Esto es útil para identificar a qué página llegó el usuario.

Crea archivos de configuración y, luego, inicia

En el directorio raíz de la aplicación, crea los archivos main.py y config.py. Configura tu clave secreta en config.py.

import os

class Config(object):
    # Note: A secret key is included in the sample so that it works.
    # If you use this code in your application, replace this with a truly secret
    # key. See https://flask.palletsprojects.com/quickstart/#sessions.
    SECRET_KEY = os.environ.get(
        'SECRET_KEY') or "REPLACE ME - this value is here as a placeholder."

En el archivo main.py, importa el módulo y, luego, inicia el servidor de Flask.

from webapp import app

if __name__ == "__main__":
    # Run the application over HTTPs with a locally stored certificate and key.
    # Defaults to https://localhost:5000.
    app.run(
        host="localhost",
        ssl_context=("localhost.pem", "localhost-key.pem"),
        debug=True)

Node.js

Las rutas se registran en el archivo app.js con las siguientes líneas.

const websiteRouter = require('./routes/index');
const addonRouter = require('./routes/classroom-addon');

app.use('/', websiteRouter);
app.use('/classroom-addon', addonRouter);

Abre /01-basic-app/routes/index.js y revisa el código. Se accede a esta ruta cuando el usuario final visita el sitio web de la empresa. La ruta procesa una respuesta con la plantilla de Handlebars index y pasa a la plantilla un objeto de datos que contiene las variables title y message.

router.get('/', function (req, res, next) {
  res.render('index', {
    title: 'Education Technology',
    message: 'Welcome to our website!'
  });
});

Abre la segunda ruta /01-basic-app/routes/classroom-addon.js y revisa el código. Se alcanza esta ruta cuando el usuario final visita el complemento. Ten en cuenta que esta ruta usa la plantilla de Handlebars discovery y, además, el diseño addon.hbs para renderizar la página de manera diferente al sitio web de la empresa.

router.get('/', function (req, res, next) {
  res.render('discovery', {
    layout: 'addon.hbs',
    title: 'Education Technology Classroom add-on',
    message: `Welcome.`
});
});

Java

En el ejemplo de código de Java, se usan módulos para empaquetar los pasos de la explicación secuencial. Como esta es la primera explicación, el código se encuentra en el módulo step_01_basic_app. No se espera que implementes el proyecto usando módulos. En su lugar, te sugerimos que compiles en un solo proyecto a medida que sigues cada paso de la explicación.

Crea una clase de controlador, Controller.java en este proyecto de ejemplo, para definir los extremos. En este archivo, importa la anotación @GetMapping desde la dependencia spring-boot-starter-web.

import org.springframework.web.bind.annotation.GetMapping;

Incluye la anotación del controlador del framework de Spring sobre la definición de la clase para indicar el propósito de la clase.

@org.springframework.stereotype.Controller
public class Controller {

Luego, implementa las dos rutas y una ruta adicional para el manejo de errores.

/** Returns the index page that will be displayed when the add-on opens in a
*   new tab.
*   @param model the Model interface to pass error information that's
*   displayed on the error page.
*   @return the index page template if successful, or the onError method to
*   handle and display the error message.
*/
@GetMapping(value = {"/"})
public String index(Model model) {
  try {
    return "index";
  } catch (Exception e) {
    return onError(e.getMessage(), model);
  }
}

/** Returns the add-on discovery page that will be displayed when the iframe
*   is first opened in Classroom.
*   @param model the Model interface to pass error information that's
*   displayed on the error page.
*   @return the addon-discovery page.
*/
@GetMapping(value = {"/addon-discovery"})
public String addon_discovery(Model model) {
  try {
    return "addon-discovery";
  } catch (Exception e) {
    return onError(e.getMessage(), model);
  }
}

/** Handles application errors.
*   @param errorMessage message to be displayed on the error page.
*   @param model the Model interface to pass error information to display on
*   the error page.
*   @return the error page.
*/
@GetMapping(value = {"/error"})
public String onError(String errorMessage, Model model) {
  model.addAttribute("error", errorMessage);
  return "error";
}

Prueba el complemento

Inicia tu servidor. Luego, accede a Google Classroom como uno de los usuarios de la prueba Teacher. Navega a la pestaña Trabajo en clase y crea una Tarea nueva. Haz clic en el botón Complementos debajo del área de texto y, luego, selecciona tu complemento. Se abrirá el iframe y el complemento cargará el URI de configuración de archivos adjuntos que especificaste en la página Configuración de la app del SDK de GWM.

¡Felicitaciones! Ya puedes continuar con el siguiente paso: acceder a los usuarios con el SSO de Google.