La pasada semana tuve la fortuna de participar como ponente en la 1ª DotNet Conference que se realizó en Alcalá de Henares. En la sesión que impartí, mostré cómo las nuevas API’s de Office 365 se pueden utilizar en cualquier dispositivo y de diversas formas. En este post, voy a profundizar un poco en cómo utilizar las API’s de Office 365 mediante Cordova haciendo uso de un framework JavaScript como AngularJS.
Requisitos
Antes de empezar el desarrollo debemos tener instalado en nuestro equipo:
- Visual Studio Update 3 o 4
- Office Tools Developer para Visual Studio
- Tools para Apache Cordova dentro de Visual Studio
Manos a la obra
Abrimos Visual Studio y creamos un proyecto Javascript -> Apache Cordova
A continuación, a nuestro proyecto le vamos a añadir la conexión a los servicios REST de la API de Office 365. Para añadirlos, nos dirigimos al Explorador de soluciones, Agregar Servicio conectado tal y como se muestra en la siguiente imagen:
Aparecerá el Administrador de servicios. Seleccionamos Office365, con lo cual registrará automáticamente nuestra APP en el Directory Activo de Azure vinculado a nuestro tenant. Introducimos los datos de usuario y contraseña de la cuenta de Office 365 que se vaya a utilizar. Una vez autentificado, veremos una lista de servicios disponibles para utilizar. Inicialmente, la columna Permisos a la derecha de cada servicio estará vacía. En nuestro ejemplo vamos a seleccionar Contacts. Una vez seleccionado pulsamos Aceptar (Imagen 2).
A continuación, si vemos nuestro proyecto, se ha creado una carpeta «Services» dónde hay una serie de ficheros js en los que están las funciones para la conexión con las API’s de Office 365 y un fichero «settings.js» dónde esta almacenados los datos de autenticación de la aplicación como son ClientID, AuthorityLogin y la Uri de Redirect (que apunta a una página añadida que se llama redirect.html)
Una vez que ya tenemos los métodos a nuestra solución, el siguiente paso es añadir una referencia en nuestra página de inicio que apunte a AngularJS. Para quien no conozca Angular es un framework desarrollado por Google, el más utilizado por los desarrolladores Front-End. Se caracteriza por extender el HTML añadiendo etiquetas y aspectos que facilitan la vida al desarrollador. Algunos especialistas no son muy partidarios de esta característica porque que es demasiado intrusiva en el HTML.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
Toda aplicación de Angular empieza en el lugar donde está la etiqueta «ng-app». A continuación, en el html podemos realizar diversas marcas como, por ejemplo, a partir de que lugar se muestra un controlador, una view o un simple dato del modelo, todos estos atributos se caracterizan porque empiezan por las «ng-loquesea». Para nuestro ejemplo, dejaremos un html inicial como el siguiente:
<!DOCTYPE html>
<html ng-app="app365">
<head>
<meta charset="utf-8" />
<title>BlankCordovaApp3</title>
<script src="services/office365/scripts/o365loader.js"></script>
<script src="services/office365/settings/settings.js"></script>
<script src="scripts/index.js"></script>
<script src="scripts/angular.js"></script>
<script src="scripts/angular-route.js"></script>
<script src="scripts/js/app.js"></script>
<script src="scripts/js/serviceO365.js"></script>
<script src="scripts/js/sign-in-ctrl.js"></script>
<script src="scripts/js/contact-list-ctrl.js"></script>
<link href="css/index.css" rel="stylesheet" />
</head>
<body>
<div ng-view></div>
</body>
</html>
En este proyecto, en el primer caso vamos a implementar un «factory» o servicio donde vamos a implementar los métodos para hacer login y logout de tal forma que tengamos totalmente desacoplado Office365 de nuestro desarrollo. Quedaría de la siguiente forma:
(function () {
'use strict';
angular.module('app365').factory('app365api', [app365api]);
function app365api() {
var authContext;
var authtoken;
var outlookClient;
var userName;
// Login to O365
function login(callback) {
if (!authContext) {
authContext = new O365Auth.Context();
}
authContext.getIdToken("https://outlook.office365.com/")
.then((function (token) {
// Get auth token.
authtoken = token;
// Get user name from token object.
userName = token.givenName + " " + token.familyName;
// Create Outlook client object.
outlookClient = new Microsoft.OutlookServices.Client('https://outlook.office365.com/api/v1.0', authtoken.getAccessTokenFn('https://outlook.office365.com'));
// Callback without parameter to indicate successful sign-in.
callback();
}).bind(this), function (reason) {
// Log sign-in error message.
console.log('Failed to login. Error = ' + reason.message);
callback(reason.message);
});
};
// Logout
function logout() {
if (!authContext) {
authContext = new O365Auth.Context();
}
authContext.logOut();
};
// Get signed-in user name
function getUserName() {
return userName;
};
return {
login: login,
logout: logout,
getUserName: getUserName,
outlookClientObj: function () { return outlookClient; }
};
};
})();
Este modulo es totalmente utilizable en cualquier otro desarrollo que realicemos haciendo uso de las API’s de Office365. Una vez ya tenemos la función para autenticarnos contra Office365, el siguiente paso es implementar el controlador de «Login». Este Controlador tan solo dispone de un método que lo que realiza. Es una llamada al método login implementado anteriormente y cuando devuelve correctamente accede a la siguiente página de la aplicación:
(function () {
'use strict';
angular.module('app365').controller('signInCtrl', ['$scope', '$location', 'app365api', signInCtrl]);
function signInCtrl($scope, $location , app365api) {
$scope.signIn = function () {
app365api.login(onlogin);
};
var onlogin = function (reason) {
$location.path("/home");
};
}
})();
Para finalizar este ejemplo, una vez ya estamos autenticados vamos a solicitar los contactos que hay en nuestra cuenta. Para ello quedaría un controlador similar al siguiente:
(function () {
'use strict';
angular.module('app365').controller('contactCtrl', ['$scope', 'app365api', contactCtrl]);
function contactCtrl($scope, app365api) {
var vm = this;
var outlookClient;
function getContacts() {
// Fetch all the contacts.
outlookClient.me.contacts.getContacts().fetch()
.then(function (contacts) {
// Get the current page. Use getNextPage() to fetch next set of contacts.
vm.contacts = contacts.currentPage;
$scope.$apply();
});
};
vm.loadList = function () {
// Get the Outlook client object.
outlookClient = app365api.outlookClientObj();
// Get contacts.
getContacts();
};
vm.loadList();
}
})();
Todos estos controladores tienen un html asociado. Esta asociación se puede hacer de forma explicita dentro de un html o bien en el fichero javascript donde creamos la aplicación. Para una aplicación más o menos «grande», realizaremos esta asignación en el fichero de inicialización de la App. En nuestro ejemplo disponemos de un fichero app.js con el siguiente contenido:
var app365 = angular.module('app365', [
'ngRoute']);
app365.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/sign-in.html',
controller: 'signInCtrl'
}).
when('/home', {
templateUrl: 'partials/contact-list.html',
controller: 'contactCtrl'
});
}
]);
Un ejemplo de uno de estos html es el siguiente:
<div class="has-header">
<div>
<div ng-repeat="contact in contacts | orderBy: 'displayName'" item-type="item item-icon-left">
{{ contact.displayName }}
</div>
</div>
</div>
Este html lo que indica es por cada valor que tenemos en la variable del controlador contacts muestra un div con su nombre.
Conclusión
Office 365 es un claro ejemplo del objetivo que ha marcado Satya Natella: poder consumir servicios de Microsoft en cualquier dispositivo y lugar. Esto abre una multitud de aspectos en los que poder extender Office 365 y adaptarla a necesidades reales de los clientes. Tiene un doble objetivo: por un lado acercar a más desarrolladores a utilizar tecnología Microsoft y por otro lado dar oportunidad para mejorar un producto.
En este ejemplo, hemos visto lo sencillo que es utilizar Cordova con Office365, ayudándonos de una de las herramientas más utilizadas por los desarrolladores.
Este ejemplo lo podeís descargar desde mi repositorio de GitHub.