forked from FarmMaps/FarmMapsApiClient
373 lines
15 KiB
C#
373 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Mime;
|
|
using System.Security.Authentication;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using FarmmapsApi.Models;
|
|
using Google.Apis.Http;
|
|
using Google.Apis.Upload;
|
|
using IdentityModel;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using Winista.Mime;
|
|
|
|
namespace FarmmapsApi.Services
|
|
{
|
|
public class FarmmapsApiService
|
|
{
|
|
private readonly Configuration _configuration;
|
|
private readonly HttpClientSettings _httpClientSettings;
|
|
private readonly HttpClient _httpClient;
|
|
private readonly OpenIdConnectService _openIdConnectService;
|
|
|
|
public FarmmapsApiService(HttpClientSettings httpClientSettings, HttpClient httpClient,
|
|
OpenIdConnectService openIdConnectService, Configuration configuration)
|
|
{
|
|
_configuration = configuration;
|
|
_httpClientSettings = httpClientSettings;
|
|
_httpClient = httpClient;
|
|
_openIdConnectService = openIdConnectService;
|
|
|
|
_httpClient.BaseAddress = new Uri(configuration.Endpoint);
|
|
_httpClient.DefaultRequestHeaders.Add("Accept", MediaTypeNames.Application.Json);
|
|
|
|
if (!string.IsNullOrEmpty(_httpClientSettings.BearerToken))
|
|
{
|
|
_httpClient.DefaultRequestHeaders.Authorization =
|
|
new AuthenticationHeaderValue(OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer,
|
|
_httpClientSettings.BearerToken);
|
|
}
|
|
}
|
|
|
|
public async Task AuthenticateAsync()
|
|
{
|
|
if (_httpClient.DefaultRequestHeaders.Authorization != null &&
|
|
_httpClient.DefaultRequestHeaders.Authorization.Scheme !=
|
|
OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer)
|
|
throw new AuthenticationException("Already seems to be authenticated");
|
|
|
|
var disco = await _openIdConnectService.GetDiscoveryDocumentAsync();
|
|
|
|
var usePasswordGrant = string.IsNullOrEmpty(_configuration.ClientId) ||
|
|
string.IsNullOrEmpty(_configuration.ClientSecret);
|
|
|
|
var token = usePasswordGrant ?
|
|
await _openIdConnectService.GetTokenUsernamePasswordAsync(disco.TokenEndpoint,
|
|
_configuration.GrantClientId, _configuration.Username, _configuration.Password) :
|
|
await _openIdConnectService.GetTokenClientCredentialsAsync(disco.TokenEndpoint,
|
|
_configuration.ClientId, _configuration.ClientSecret);
|
|
|
|
if (token.IsError)
|
|
throw new AuthenticationException(token.Error);
|
|
|
|
_httpClientSettings.BearerToken = token.AccessToken;
|
|
_httpClient.DefaultRequestHeaders.Authorization =
|
|
new AuthenticationHeaderValue(OidcConstants.AuthenticationSchemes.AuthorizationHeaderBearer,
|
|
token.AccessToken);
|
|
}
|
|
|
|
public async Task<string> GetCurrentUserCodeAsync()
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.CURRENTUSER_RESOURCE}";
|
|
var response = await _httpClient.GetAsync(url);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
var json = JsonConvert.DeserializeObject<JObject>(jsonString);
|
|
return json["code"].Value<string>();
|
|
}
|
|
|
|
public async Task<List<UserRoot>> GetCurrentUserRootsAsync()
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.MYROOTS_RESOURCE}";
|
|
var response = await _httpClient.GetAsync(url);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
|
|
return JsonConvert.DeserializeObject<List<UserRoot>>(jsonString);
|
|
}
|
|
|
|
public async Task<Item> GetItemAsync(string itemCode, string itemType = null, JObject dataFilter = null)
|
|
{
|
|
if (dataFilter == null)
|
|
return await GetItemSingleAsync(itemCode, itemType);
|
|
|
|
var items = await GetItemsAsync(itemCode, itemType, dataFilter);
|
|
return items[0];
|
|
}
|
|
|
|
public async Task<List<Item>> GetItemsAsync(string itemCode, string itemType = null, JObject dataFilter = null)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
|
|
var queryString = HttpUtility.ParseQueryString(string.Empty);
|
|
|
|
if (itemType != null)
|
|
queryString["it"] = itemType;
|
|
|
|
if (dataFilter != null)
|
|
queryString["df"] = dataFilter.ToString(Formatting.None);
|
|
|
|
resourceUri = (queryString.Count > 0 ? $"{resourceUri}?" : resourceUri) + queryString;
|
|
|
|
var response = await _httpClient.GetAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode == HttpStatusCode.NotFound)
|
|
return null;
|
|
|
|
throw new Exception(response.ReasonPhrase);
|
|
}
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<List<Item>>(jsonString);
|
|
}
|
|
|
|
private async Task<Item> GetItemSingleAsync(string itemCode, string itemType = null)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
|
|
if (!string.IsNullOrEmpty(itemType))
|
|
resourceUri = $"{resourceUri}/{itemType}";
|
|
|
|
var response = await _httpClient.GetAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode == HttpStatusCode.NotFound)
|
|
return null;
|
|
|
|
throw new Exception(response.ReasonPhrase);
|
|
}
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<Item>(jsonString);
|
|
}
|
|
|
|
public async Task<List<Item>> GetItemChildrenAsync(string itemCode, string itemType = null,
|
|
JObject dataFilter = null)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_CHILDREN_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
|
|
var queryString = HttpUtility.ParseQueryString(string.Empty);
|
|
|
|
if (itemType != null)
|
|
queryString["it"] = itemType;
|
|
|
|
if (dataFilter != null)
|
|
queryString["df"] = dataFilter.ToString(Formatting.None);
|
|
|
|
resourceUri = (queryString.Count > 0 ? $"{resourceUri}?" : resourceUri) + queryString;
|
|
|
|
var response = await _httpClient.GetAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<List<Item>>(jsonString);
|
|
}
|
|
|
|
public async Task<Item> CreateItemAsync(ItemRequest itemRequest)
|
|
{
|
|
var jsonString = JsonConvert.SerializeObject(itemRequest);
|
|
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_CREATE_RESOURCE}";
|
|
var content = new StringContent(jsonString, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
var response = await _httpClient.PostAsync(url,
|
|
content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonStringResponse = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<Item>(jsonStringResponse);
|
|
}
|
|
|
|
public async Task DeleteItemAsync(string itemCode)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
var response = await _httpClient.DeleteAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
}
|
|
|
|
public async Task DeleteItemsAsync(IList<string> itemCodes)
|
|
{
|
|
var jsonString = JsonConvert.SerializeObject(itemCodes);
|
|
var content = new StringContent(jsonString);
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_DELETE_RESOURCE}";
|
|
var response = await _httpClient.PostAsync(url, content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
}
|
|
|
|
public async Task DownloadItemAsync(string itemCode, string filePath)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_DOWNLOAD_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
var response = await _httpClient.GetAsync(resourceUri, HttpCompletionOption.ResponseHeadersRead);
|
|
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
await using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync();
|
|
await using Stream streamToWriteTo = File.Open(filePath, FileMode.Create);
|
|
await streamToReadFrom.CopyToAsync(streamToWriteTo);
|
|
}
|
|
else
|
|
{
|
|
throw new FileNotFoundException(response.ReasonPhrase);
|
|
}
|
|
}
|
|
|
|
public async Task<string> QueueTaskAsync(string itemCode, TaskRequest taskRequest)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMTASK_REQUEST_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
|
|
var jsonString = JsonConvert.SerializeObject(taskRequest);
|
|
var content = new StringContent(jsonString, Encoding.UTF8, MediaTypeNames.Application.Json);
|
|
var response = await _httpClient.PostAsync(resourceUri, content);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonStringResponse = await response.Content.ReadAsStringAsync();
|
|
var json = JsonConvert.DeserializeObject<JObject>(jsonStringResponse);
|
|
|
|
return json["code"].Value<string>();
|
|
}
|
|
|
|
public async Task<List<ItemTaskStatus>> GetTasksStatusAsync(string itemCode)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMTASKS_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode);
|
|
var response = await _httpClient.GetAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<List<ItemTaskStatus>>(jsonString);
|
|
}
|
|
|
|
public async Task<ItemTaskStatus> GetTaskStatusAsync(string itemCode, string itemTaskCode)
|
|
{
|
|
var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMTASK_RESOURCE}";
|
|
var resourceUri = string.Format(url, itemCode, itemTaskCode);
|
|
var response = await _httpClient.GetAsync(resourceUri);
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
throw new Exception(response.ReasonPhrase);
|
|
|
|
var jsonString = await response.Content.ReadAsStringAsync();
|
|
return JsonConvert.DeserializeObject<ItemTaskStatus>(jsonString);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Experimental
|
|
/// </summary>
|
|
/// <param name="filePath"></param>
|
|
/// <param name="parentItemCode"></param>
|
|
/// <param name="progressCallback"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="FileNotFoundException"></exception>
|
|
public async Task<UploadResults> UploadFile(string filePath, string parentItemCode,
|
|
string geoJsonString = null,
|
|
Action<IUploadProgress> progressCallback = null)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
throw new FileNotFoundException($"File not found {filePath}");
|
|
|
|
var mimeTypes = new MimeTypes();
|
|
var mimeType = mimeTypes.GetMimeTypeFromFile(filePath);
|
|
|
|
var mimeString = mimeType?.ToString() ?? "application/json";
|
|
|
|
await using var uploadStream = new FileStream(filePath, FileMode.OpenOrCreate);
|
|
|
|
var request = new FileRequest()
|
|
{
|
|
Name = Path.GetFileName(filePath),
|
|
ParentCode = parentItemCode,
|
|
Size = uploadStream.Length,
|
|
Geometry = string.IsNullOrEmpty(geoJsonString) ? null : JObject.Parse(geoJsonString)
|
|
};
|
|
|
|
using var httpClient = CreateConfigurableHttpClient(_httpClient);
|
|
var farmmapsUploader = new FarmmapsUploader(httpClient, uploadStream, request,
|
|
mimeString, ResourceEndpoints.ITEMS_UPLOAD_RESOURCE);
|
|
|
|
Uri location = null;
|
|
farmmapsUploader.ProgressChanged += progressCallback;
|
|
farmmapsUploader.UploadSessionData += data => location = data.UploadUri;
|
|
|
|
var progress = await farmmapsUploader.UploadAsync();
|
|
return new UploadResults(progress, location);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Experimental
|
|
/// </summary>
|
|
/// <param name="filePath"></param>
|
|
/// <param name="location"></param>
|
|
/// <param name="uploadCallback"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="FileNotFoundException"></exception>
|
|
private async Task<Uri> ResumeUploadFile(string filePath, Uri location, Action<IUploadProgress> uploadCallback)
|
|
{
|
|
if (!File.Exists(filePath))
|
|
throw new FileNotFoundException($"File not found {filePath}");
|
|
|
|
await using var uploadStream = new FileStream(filePath, FileMode.OpenOrCreate);
|
|
|
|
var request = new FileRequest()
|
|
{
|
|
Name = Path.GetFileName(filePath),
|
|
ParentCode = string.Empty,
|
|
Size = uploadStream.Length
|
|
};
|
|
|
|
using var httpClient = CreateConfigurableHttpClient(_httpClient);
|
|
var farmmapsUploader = new FarmmapsUploader(httpClient, uploadStream,
|
|
request, string.Empty, ResourceEndpoints.ITEMS_UPLOAD_RESOURCE);
|
|
farmmapsUploader.ProgressChanged += uploadCallback;
|
|
|
|
await farmmapsUploader.ResumeAsync(location);
|
|
|
|
return location;
|
|
}
|
|
|
|
private ConfigurableHttpClient CreateConfigurableHttpClient(HttpClient parent)
|
|
{
|
|
var googleHttpClient = new HttpClientFactory().CreateHttpClient(new CreateHttpClientArgs
|
|
{GZipEnabled = true, ApplicationName = "FarmMaps"});
|
|
googleHttpClient.BaseAddress = parent.BaseAddress;
|
|
googleHttpClient.DefaultRequestHeaders.Add("Accept", MediaTypeNames.Application.Json);
|
|
|
|
var authHeader = parent.DefaultRequestHeaders.Authorization;
|
|
googleHttpClient.DefaultRequestHeaders.Authorization =
|
|
new AuthenticationHeaderValue(authHeader.Scheme, authHeader.Parameter);
|
|
|
|
return googleHttpClient;
|
|
}
|
|
}
|
|
} |