Создаем приложение для OneDrive с помощью AngularJS и Microsoft API

12 сентября 2016 г.

Microsoft API - богатый и постоянно растущий API, который позволяет легко создавать приложения для работы с данными, расположенными в облаке Office 365. В этом посте я покажу как можно создать веб-приложение для работы с OneDrive, используя Microsoft API.

Задача

В качестве примеры создадим веб-приложение не привязанное к какой-либо платформе (только HTML, CSS и JavaScript). Приложение должно содержать следующие функции:

  • Отображать содержимое OneDrive (папки, файлы) с возможностью навигации по папкам
  • Создавать, переименовывать и удалять папки/файлы
  • Осуществлять поиск в OneDrive

Отображаться должны только файлы текущего пользователя.

Как это будет работать

Веб-приложение будет построено на AngularJS 1.x без использования какого-либо серверного кода. В качестве 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 API, задача авторизации пользователя решается крайне просто: два js-файла и две сроки кода. Безопасность и разграничение прав пользователей также на стороне Office 365.

REST API

Для доступа к OneDrive пользователя будем использовать Microsoft API. Здесь мы имеем единый endpoint, что сильно облегчает работу. Например для получения информации о файлах и папках в корне OneDrive для текущего пользователя достаточно выполнить запрос:


GET https://graph.microsoft.com/v1.0/me/drive/root/children

Результат этого запроса в Graph Explorer:

Microsoft Graph Explorer

Документацию по методам для работы с элементами OneDrive можно посмотреть здесь.

Приложение

Чтобы подключаться к Microsoft API необходимо зарегистрировать своё приложение 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(args);
    }
}

Единственная его задача - указать файл по умолчанию (default.html) и разрешить использование статичных файлов (метод UseStaticFiles). Все остальное - JavaScript, HTML и CSS.

Пакеты, которые используются в приложении:

Инициализация приложения выглядит примерно вот так:


// 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 API - это всегда 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-архиве.

Смотрите также

Microsoft Graph. Подключение к данным

Microsoft Graph Explorer

AngularJS — фреймворк для динамических веб-приложений от Google

Презентация с доклада о Microsoft API и Office Graph

Поделиться

Комментарии