ADN Open CIS
Сообщество программистов Autodesk в СНГ

29/11/2019

Получаем количество проектов BIM360 для каждого пользователя

Существует множество способов получения данных BIM 360 для создания разнообразных отчетов. Часто встречается вопрос, как получить количество или список проектов для конкретного пользователя. Это возможно реализовать с помощью комбинации BIM 360 API и Data Management API. Давайте разберемся, как получить эту информацию и создадим отчет с гистограммой.

Для этого:

1. Получим 2 legged access токен доступа, обязательно указав scopes: "account:read" и "data:read "

2. Получим перечень пользователей аккаунта BIM 360 (GET users)

3. Для каждого пользователя получим перечень проектов с помощью метода API GET projects, передав в запросе заголовок x-user-id со значением user.uid.

Вот, фактически и всё. С помощью простых манипуляций с JSON объединяем данные из пунктов 2 и 3. Но есть один нюанс. Количество пользователей аккаунта BIM 360 может быть достаточно большим и, соответственно, при получении проектов метод GET projects может вернуть результат "Превышен лимит количества запросов". Существуют разные способы обхода данной проблемы. В этой статье мы воспользуемся одним из самых простых.

Серверный код (пример на C#) для получения списка пользователей (имя и uid), предполагаем, что регион - US, получаем все страницы (до 100 пользователей на каждой странице):

Код - C#: [Выделить]
  1. public async Task<JArray> GetUsers(string hubId, string accessToken, JArray users = null, int offset = 0)
  2. {
  3.     users = (users == null ? new JArray() : users);
  4.     RestClient client = new RestClient(BASE_URL);
  5.     RestRequest request = new RestRequest("/hq/v1/accounts/{account_id}/users?limit={limit}&offset={offset}&field=name,uid", RestSharp.Method.GET);
  6.     request.AddParameter("account_id", hubId.Replace("b.", string.Empty), ParameterType.UrlSegment);
  7.     request.AddParameter("limit", 100);
  8.     request.AddParameter("offset", offset);
  9.     request.AddHeader("Authorization", "Bearer " + accessToken);
  10.     IRestResponse response = await client.ExecuteTaskAsync(request);
  11.     if (response.StatusCode != HttpStatusCode.OK) return null;
  12.     JArray page = JArray.Parse(response.Content);
  13.     users.Merge(page);
  14.     if (page.Count >= 100) await GetUsers(hubId, accessToken, users, offset += 100);
  15.     return users;
  16. }

Получаем проекты: есть большая вероятность превышения лимита количества запросов, поэтому в таком случае повторяем запрос через n секунд, значение n берем из полученного заголовка Retry-After.

Код - C#: [Выделить]
  1. public async Task<JObject> GetProjectsAsync(string hubId, string userId, string accessToken, int attempt = 0)
  2. {
  3.     RestClient client = new RestClient(BASE_URL);
  4.     RestRequest request = new RestRequest("project/v1/hubs/{hubId}/projects", RestSharp.Method.GET);
  5.     request.AddParameter("hubId", hubId, ParameterType.UrlSegment);
  6.     request.AddHeader("Authorization", "Bearer " + accessToken);
  7.     request.AddHeader("x-user-id", userId);
  8.     IRestResponse response = await client.ExecuteTaskAsync(request);
  9.     if (response.StatusCode == HttpStatusCode.OK)
  10.         return JObject.Parse(response.Content);
  11.     else if (response.StatusCode == HttpStatusCode.TooManyRequests)
  12.     {
  13.         if (attempt > 5) return null;
  14.         int retryAfter = int.Parse(response.Headers.ToList().Find(h => h.Name == "Retry-After").Value.ToString());
  15.         System.Threading.Thread.Sleep(retryAfter * 1000);
  16.         return await GetProjectsAsync(hubId, userId, accessToken, ++attempt);
  17.     }
  18.     return null;
  19. }

Теперь создадим метод MVC-контроллера, принимающий hubId (или id аккаунта) и возвращающий список пользователей, отсортированный по количеству проектов:

Код - C#: [Выделить]
  1. [HttpGet]
  2. [Route("api/forge/bim360/hubs/{hubId}/users")]
  3. public async Task<JArray> GetProjectByUser(string hubId)
  4. {
  5.     TwoLeggedApi oauth = new TwoLeggedApi();
  6.     dynamic bearer = await oauth.AuthenticateAsync(GetAppSetting("FORGE_CLIENT_ID"), GetAppSetting("FORGE_CLIENT_SECRET"), "client_credentials", new Scope[] { Scope.AccountRead, Scope.DataRead });
  7.     JArray users = await GetUsers(hubId, bearer.access_token);
  8.     foreach (dynamic user in users)
  9.     {
  10.         user.projects = new JArray();
  11.         user.projects_count = 0;
  12.  
  13.         if (user.uid == null) continue; // not activated yet
  14.         dynamic projects = await GetProjectsAsync(hubId, (string)user.uid, (string)bearer.access_token);
  15.         if (projects == null) continue;
  16.         foreach (dynamic project in projects.data)
  17.         {
  18.             dynamic projectInfo = new JObject();
  19.             projectInfo.name = project.attributes.name;
  20.             projectInfo.id = project.id;
  21.             user.projects.Add(projectInfo);
  22.         }
  23.         user.projects_count = ((JArray)user.projects).Count;
  24.     }
  25.  
  26.     return new JArray(users.OrderByDescending(u => (int)u["projects_count"]));
  27. }

Здесь предполагается, что в Вашем коде есть метод GetAppSettings, который возвращает Client Id и Client Secret приложения Forge.

С помощью Chartjs нарисуем гистограмму:

Код - HTML: [Выделить]
  1. <script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.bundle.min.js"></script>
  2.     $(document).ready(function () {
  3.         jQuery.ajax({
  4.             url: '/api/forge/bim360/hubs/YOUR_ACCOUNT_ID_HERE/users',
  5.             success: function (users) {
  6.                 var labels = [];
  7.                 var data = [];
  8.                 users.forEach(function (user) {
  9.                     if (user.projects_count <= 3) return;
  10.                     labels.push(user.name);
  11.                     data.push(user.projects_count);
  12.                 });
  13.  
  14.                 var context = document.getElementById('projectsPerUser').getContext('2d');
  15.                 var barChart = new Chart(context, {
  16.                     type: 'bar',
  17.                     data: {
  18.                         labels: labels,
  19.                         datasets: [{
  20.                             label: 'Projects',
  21.                             data: data,
  22.                             backgroundColor: getRandomColor(data.length)
  23.                         }]
  24.                     },
  25.                     options: {
  26.                         responsive: true,
  27.                         legend: {
  28.                             position: 'top',
  29.                         },
  30.                         title: {
  31.                             display: true,
  32.                             text: 'BIM 360 user statistics'
  33.                         },
  34.                         scales: {
  35.                             yAxes: [{
  36.                                 ticks: {
  37.                                     beginAtZero: true
  38.                                 }
  39.                             }]
  40.                         }
  41.                     }
  42.                 });
  43.             }
  44.         });
  45.     });
  46.  
  47.     function getRandomColor(count) {
  48.         var colors = [];
  49.         for (var i = 0; i < count; i++) {
  50.             var r = Math.round(Math.random() * 255); var g = Math.round(Math.random() * 255); var b = Math.round(Math.random() * 255);
  51.             colors.push('rgba(' + r + ', ' + g + ', ' + b + ', 0.2)');
  52.         }
  53.         return colors;
  54.     }
  55. <div style="width:100%;">
  56.     <canvas id="projectsPerUser"></canvas>
  57. </div>

Источник: https://forge.autodesk.com/blog/get-number-bim-360-projects-user

Автор перевода: Александр Игнатович
Опубликовано 29.11.2019