Создаем приложение для OneDrive с помощью AngularJS и Microsoft API
Microsoft Graph - богатый и постоянно растущий API, который позволяет легко создавать приложения для работы с данными, расположенными в Office 365. В этом посте я покажу как можно создать веб-приложение для работы с OneDrive, используя Microsoft Graph.
Задача
В качестве примеры создадим веб-приложение не привязанное к какой-либо платформе (только HTML, CSS и JavaScript). Приложение должно содержать следующие функции:
- Отображать содержимое OneDrive (папки, файлы) с возможностью навигации по папкам
- Создавать, переименовывать и удалять папки/файлы
- Осуществлять поиск в OneDrive
Отображаться должны только файлы текущего пользователя.
Как это будет работать
Веб-приложение будет построено на AngularJS без использования какого-либо серверного кода. В качестве UI Framework будет использован Bootstrap.
Авторизация
Для авторизации будет использован Azure AD Authentication Library (ADAL). В случае с AngularJS для реализации такой аутентификации достаточно подключить следующие js-файлы:
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.7/js/adal.min.js"></script>
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.7/js/adal-angular.min.js"></script>
После чего авторизация будет инициироваться вызовом метода:
//AngularJS ADAL login
adalAuthenticationService.login();
Logout соответственно:
//AngularJS ADAL logout
adalAuthenticationService.logOut();
Создавая решения на базе Office 365 и Microsoft Graph, задача авторизации пользователя решается крайне просто: два js-файла и две сроки кода. Безопасность и разграничение прав пользователей также на стороне Office 365.
REST API
Для доступа к OneDrive пользователя будем использовать Microsoft Graph. Здесь мы имеем единый endpoint, что сильно облегчает работу. Например для получения информации о файлах и папках в корне OneDrive для текущего пользователя достаточно выполнить запрос:
GET: https://graph.microsoft.com/v1.0/me/drive/root/children
Результат этого запроса в Graph Explorer:
Документацию по методам для работы с элементами OneDrive можно посмотреть здесь.
Приложение
Чтобы подключаться к Microsoft Graph необходимо зарегистрировать своё приложение в Azure Portal и предоставить ему соответствующие права.
Шаг 1. Создаем приложение
Переходим к списку приложений (Active Directory - {ДОМЕН} - Applications) и нажимаем Add:
Приложение мы создаем своё, а не выбираем существующее из галереи, выбираем Add an application my organization is developing:
Затем указываем имя приложения, выбираем ""Web application and/or web api", задаем любой App ID URI.
Адрес Sign-On необходимо указывать существующий. При несовпадении URL-адреса, с которого происходит авторизация, с теми, что указаны в настройках приложения будет выдано исключение
AADSTS50011: The reply address '{URL}' does not match the reply addresses configured for the application
Для работы нам понадобиться CLIENT ID. Скопировать его можно со страницы настройки приложения:
Шаг 2. Права приложения
Создаваемому приложению необходимо предоставить соответствующие права (для работы с OneDrive):
- Files.Read
- Files.ReadWrite
Этих прав достаточно для создания/изменения/удаления элементов, изменения прав на файлы, папки, поиск. Настройка прав на той же странице конфигурации приложения:
Шаг 3. Visual Studio
Я использовал Visual Studio 2015 и шаблон веб-приложения ASP.NET 5 для удобства. Visual Studio можно было бы не использовать вовсе, ограничившись бесплатной Visual Studio Code для работы с кодом и npm или Bower для установки пакетов.
Серверная часть приложения - это файл satrtup.cs:
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.StaticFiles;
namespace Zhukov.Blog.Graph.AngularJS
{
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseIISPlatformHandler();
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("default.html");
// Файл по умолчанию
app.UseDefaultFiles(options);
// Статические файлы
app.UseStaticFiles();
}
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
Единственная его задача - указать файл по умолчанию (default.html) и разрешить использование статичных файлов (метод UseStaticFiles). Все остальное - JavaScript, HTML и CSS.
Пакеты, которые используются в приложении:
- jQuery;
- Bootstrap - UI Framework;
- Font Awesome - бесплатный набор иконок в виде шрифтов;
- AngularJS - JS Framework;
- ngRoute - роутинг для AngularJS, обеспечит переключение представление в нашем Single Page Application;
- Angular loading bar - автоматический индикатор загрузки для визуального отображения процесса обработки запроса.
Инициализация приложения выглядит примерно вот так:
// CLIENT ID from https://manage.windowsazure.com
var clientId = '27015206-d28a-45a6-a952-a1e987edf216';
// OneDrive App
var oneDriveApp = angular.module('MicrosoftGraphSPA', [
'ngRoute',
'AdalAngular',
'angular-loading-bar'
]).config(config);
function config($routeProvider, $httpProvider, adalAuthenticationServiceProvider, cfpLoadingBarProvider) {
// Routing
// ADAL
adalAuthenticationServiceProvider.init(
{
clientId: clientId, //CLIENT ID
endpoints: {
'https://graph.microsoft.com': 'https://graph.microsoft.com'
}
}, $httpProvider);
// Hide loading spinner
cfpLoadingBarProvider.includeSpinner = false;
};
Я опустил роутинг в листинге выше. Помимо него в конфигурации приложения (метод config) указывает ClientId соответствующий созданному в Azure Portal приложению на шаге 1 и скрываем индикатор загрузки для loading bar, оставив только progress bar.
Шаг 4. Сервис
Для взаимодействия с Microsoft API создадим фабрику oneDriveFactory. Логика её проста - формировать и отправлять запросы с учетом авторизации текущего пользователя. Вот сокращенный листинг:
angular
.module('MicrosoftGraphSPA')
.constant('graphUrl', 'https://graph.microsoft.com/v1.0')
.factory('oneDriveFactory',
[
'$http', 'graphUrl',
function($http, graphUrl) {
var oneDriveFactory = {};
// Получение содержимого из корня OneDrive
oneDriveFactory.getRoot = function() {
return $http({
method: 'GET',
url: graphUrl + '/me/drive/root/children'
});
};
// Переименование файла или папки
oneDriveFactory.saveItem = function(itemId, name) {
return $http({
method: 'PATCH',
url: graphUrl + '/me/drive/items/' + itemId,
data: {
name: name
}
});
};
// Создание новой папки
oneDriveFactory.addFolder = function(parentId, name) {
var url = parentId
? graphUrl + '/me/drive/items/' + parentId + '/children'
: graphUrl + '/me/drive/root/children';
return $http({
method: 'POST',
url: url,
data: {
name: name,
folder: {}
}
});
}
// Удаление файла или папки
oneDriveFactory.removeItem = function(itemId) {
return $http({
method: 'DELETE',
url: graphUrl + '/me/drive/items/' + itemId
});
}
return oneDriveFactory;
}
]);
Любая операция в Office 365 при использовании Microsoft Graph - это всегда HTTP-запрос с параметрами, что крайне облегчает разработку решений.
Загрузка файла в OneDrive с помощью Microsoft API состоит из двух операций: сначала запрос на создание файла (в ответе сервера будет указан идентификатор созданного файла), затем запрос на загрузку содержимого файла.
Шаг 5. Контроллер
Контроллеры для вызова методов фабрики также крайне прост. Листинг контроллера для результатов поиска:
(function () {
angular
.module('MicrosoftGraphSPA')
.controller('SearchController', [
'$scope', '$rootScope', '$http', '$location', 'oneDriveFactory',
function ($scope, $rootScope, $http, $location, oneDriveFactory) {
// Запрос
$scope.query = $location.search().q;
// Элементы
$scope.items = null;
// Загрузка элементов из Office 365
$scope.loadItems = function () {
oneDriveFactory.searchItems($scope.query)
.then(
function (response) {
// Заполняем items
$scope.items = response.data.value;
}, $rootScope.responseError);
}
// Если указан поисковый запрос, то заполняем items
if ($scope.query) {
$scope.loadItems();
}
}
]);
})();
Шаг 6. Роутинг
Приложение содержит три вида представления:
- Корень пользовательского OneDrive (представление по умолчанию);
- Просмотр содержимого папки;
- Отображение результатов поиска.
Соответственно листинг роутинга:
$routeProvider
// Routing
.when('/onedrive', { //Root
templateUrl: 'views/onedrive.html',
controller: 'OneDriveController',
controllerAs: 'controller'
})
.when('/onedrive/search', { //Search
templateUrl: 'views/search.html',
controller: 'SearchController',
controllerAs: 'controller'
})
.when('/onedrive/:itemId', { //File/Folder
templateUrl: 'views/onedrive.html',
controller: 'OneDriveController',
controllerAs: 'controller'
})
.otherwise({ //Root by default
redirectTo: '/onedrive'
});
Шаг 7. Интерфейс
В случае с отображением результатов поиска представление выглядит следующим образом:
<ul class="breadcrumb">
<li><a href="#/">Microsoft Graph SPA</a></li>
<li><a href="#/onedrive">OneDrive</a></li>
<li class="active">Search</li>
</ul>
<!-- Search results -->
<div class="row">
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Size</th>
<th>Created</th>
<th>Created By</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items | orderBy: 'folder'">
<td>
<i class="fa"
ng-class="item.folder ? 'fa-folder' : 'fa-file'"
aria-hidden="true"></i>
<a href="#/onedrive/{{item.id}}">{{ item.name }}</a>
</td>
<td>{{ item.file ? (item.size | bytes) : ''}}</td>
<td>{{ item.createdDateTime | date:'medium' }}</td>
<td>{{ item.createdBy.user.displayName }}</td>
</tr>
</tbody>
</table>
</div>
Навигация сверху и таблица под ней:
Вот и всё приложение.
Исходные коды
Исходные коды доступны в Developer code samples. Опубликовать приложение ASP.NET 5 на сайте code.msdn.microsoft.com нельзя, т.к. система не видит решение. Поэтому я создал аналогичное решение с шаблонов ASP.NET 4.5. Исходное доступно в zip-архиве.