forked from FarmMaps/FarmMapsApiClient
		
	Initial resumable file upload.
Other changes.
This commit is contained in:
		@@ -5,6 +5,7 @@
 | 
			
		||||
    </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
        <PackageReference Include="Google.Apis" Version="1.44.1" />
 | 
			
		||||
        <PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.2" />
 | 
			
		||||
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
 | 
			
		||||
        <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.2" />
 | 
			
		||||
@@ -12,6 +13,7 @@
 | 
			
		||||
        <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.2" />
 | 
			
		||||
        <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.2" />
 | 
			
		||||
        <PackageReference Include="IdentityModel.OidcClient" Version="3.1.2" />
 | 
			
		||||
        <PackageReference Include="Winista.MimeDetect" Version="1.0.1" />
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
    {
 | 
			
		||||
        public string Authority { get; set; } 
 | 
			
		||||
        public string Endpoint { get; set; } 
 | 
			
		||||
        public string BasePath { get; set; } 
 | 
			
		||||
        public string DiscoveryEndpointUrl { get; set; } 
 | 
			
		||||
        public string RedirectUri { get; set; } 
 | 
			
		||||
        public string ClientId { get; set; } 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								FarmmapsApi/Models/FileRequest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								FarmmapsApi/Models/FileRequest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
using System.ComponentModel.DataAnnotations;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
 | 
			
		||||
namespace FarmmapsApi.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FileRequest
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Code of the parent
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>41971e7ea8a446069a817e66b608dcae</example>
 | 
			
		||||
        public string ParentCode { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Geometry meta data
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>{"type": "Point","coordinates": [5.27, 52.10]}</example>
 | 
			
		||||
        public JObject Geometry { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Name of the file to upload
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>MyFile.tiff</example>
 | 
			
		||||
        [Required]
 | 
			
		||||
        public string Name { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Size of the file to upload
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>67351</example>      
 | 
			
		||||
        [Required]
 | 
			
		||||
        public long Size { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// If a chunked upload, the size of a single chunk
 | 
			
		||||
        /// </summary>   
 | 
			
		||||
        /// <example>1048576</example>
 | 
			
		||||
        public long ChunkSize { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Optional data for the item coupled with the file
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public JObject Data { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								FarmmapsApi/Models/FileResponse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								FarmmapsApi/Models/FileResponse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
namespace FarmmapsApi.Models
 | 
			
		||||
{
 | 
			
		||||
    public class FileResponse : FileRequest
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Code created for the registered file, use this in subsequent calls
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>a00fbd18320742c787f99f952aef0dbb</example>
 | 
			
		||||
        public string Code { get; set; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// If a chunked upload, the number of chunks to upload
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <example>1</example>
 | 
			
		||||
        public long Chunks { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,30 +10,31 @@ using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Web;
 | 
			
		||||
using FarmmapsApi.Models;
 | 
			
		||||
using Google.Apis.Http;
 | 
			
		||||
using Google.Apis.Upload;
 | 
			
		||||
using IdentityModel;
 | 
			
		||||
using Microsoft.AspNetCore.Http.Connections;
 | 
			
		||||
using Microsoft.AspNetCore.SignalR.Client;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using Winista.Mime;
 | 
			
		||||
 | 
			
		||||
namespace FarmmapsApi.Services
 | 
			
		||||
{
 | 
			
		||||
    public class FarmmapsApiService
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ILogger<FarmmapsApiService> _logger;
 | 
			
		||||
        private readonly HttpClient _httpClient;
 | 
			
		||||
        private readonly OpenIdConnectService _openIdConnectService;
 | 
			
		||||
        private readonly Configuration _configuration;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        private HubConnection _hubConnection;
 | 
			
		||||
 | 
			
		||||
        public event Action<EventMessage> EventCallback;
 | 
			
		||||
 | 
			
		||||
        public FarmmapsApiService(HttpClient httpClient, ILogger<FarmmapsApiService> logger,
 | 
			
		||||
        public FarmmapsApiService(HttpClient httpClient, 
 | 
			
		||||
            OpenIdConnectService openIdConnectService, Configuration configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
            _httpClient = httpClient;
 | 
			
		||||
            _openIdConnectService = openIdConnectService;
 | 
			
		||||
            _configuration = configuration;
 | 
			
		||||
@@ -65,10 +66,9 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        private async Task StartEventHub(string accessToken)
 | 
			
		||||
        {
 | 
			
		||||
            var uri = new Uri(_configuration.Endpoint);
 | 
			
		||||
            var eventEndpoint = $"{uri.Scheme}://{uri.Host}:{uri.Port}/EventHub";
 | 
			
		||||
            var eventEndpoint = $"{_configuration.Endpoint}/EventHub";
 | 
			
		||||
            _hubConnection = new HubConnectionBuilder()
 | 
			
		||||
                .WithUrl(eventEndpoint, HttpTransportType.WebSockets, 
 | 
			
		||||
                .WithUrl(eventEndpoint, HttpTransportType.WebSockets,
 | 
			
		||||
                    options => options.SkipNegotiation = true)
 | 
			
		||||
                .ConfigureLogging(log => log.AddConsole())
 | 
			
		||||
                .WithAutomaticReconnect()
 | 
			
		||||
@@ -76,9 +76,9 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
            await _hubConnection.StartAsync();
 | 
			
		||||
            await AuthenticateEventHub(accessToken);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            _hubConnection.Reconnected += async s => await AuthenticateEventHub(accessToken);
 | 
			
		||||
            _hubConnection.On("event", (Object @event) => _logger.LogInformation(@event.ToString()));
 | 
			
		||||
            _hubConnection.On("event", (EventMessage eventMessage) => EventCallback?.Invoke(eventMessage));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task AuthenticateEventHub(string accessToken)
 | 
			
		||||
@@ -88,7 +88,8 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        public async Task<string> GetCurrentUserCodeAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var response = await _httpClient.GetAsync(ResourceEndpoints.CURRENTUSER_RESOURCE);
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.CURRENTUSER_RESOURCE}";
 | 
			
		||||
            var response = await _httpClient.GetAsync(url);
 | 
			
		||||
 | 
			
		||||
            if (!response.IsSuccessStatusCode)
 | 
			
		||||
                throw new Exception(response.ReasonPhrase);
 | 
			
		||||
@@ -100,7 +101,8 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        public async Task<List<UserRoot>> GetCurrentUserRootsAsync()
 | 
			
		||||
        {
 | 
			
		||||
            var response = await _httpClient.GetAsync(ResourceEndpoints.MYROOTS_RESOURCE);
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.MYROOTS_RESOURCE}";
 | 
			
		||||
            var response = await _httpClient.GetAsync(url);
 | 
			
		||||
 | 
			
		||||
            if (!response.IsSuccessStatusCode)
 | 
			
		||||
                throw new Exception(response.ReasonPhrase);
 | 
			
		||||
@@ -109,7 +111,7 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
            return JsonConvert.DeserializeObject<List<UserRoot>>(jsonString);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        public async Task<Item> GetItemAsync(string itemCode, string itemType = null, JObject dataFilter = null)
 | 
			
		||||
        {
 | 
			
		||||
            if (dataFilter == null)
 | 
			
		||||
@@ -118,28 +120,29 @@ namespace FarmmapsApi.Services
 | 
			
		||||
            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 resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, itemCode);
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_RESOURCE}";
 | 
			
		||||
            var resourceUri = string.Format(url, itemCode);
 | 
			
		||||
 | 
			
		||||
            var queryString = HttpUtility.ParseQueryString(string.Empty);
 | 
			
		||||
            
 | 
			
		||||
            if(itemType != null)
 | 
			
		||||
 | 
			
		||||
            if (itemType != null)
 | 
			
		||||
                queryString["it"] = itemType;
 | 
			
		||||
            
 | 
			
		||||
            if(dataFilter != null)
 | 
			
		||||
                queryString["df"] =  dataFilter.ToString(Formatting.None);
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -149,36 +152,39 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        private async Task<Item> GetItemSingleAsync(string itemCode, string itemType = null)
 | 
			
		||||
        {
 | 
			
		||||
            var resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, itemCode);
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
        public async Task<List<Item>> GetItemChildrenAsync(string itemCode, string itemType = null,
 | 
			
		||||
            JObject dataFilter = null)
 | 
			
		||||
        {
 | 
			
		||||
            var resourceUri = string.Format(ResourceEndpoints.ITEMS_CHILDREN_RESOURCE, itemCode);
 | 
			
		||||
            
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMS_CHILDREN_RESOURCE}";
 | 
			
		||||
            var resourceUri = string.Format(url, itemCode);
 | 
			
		||||
 | 
			
		||||
            var queryString = HttpUtility.ParseQueryString(string.Empty);
 | 
			
		||||
            
 | 
			
		||||
            if(itemType != null) 
 | 
			
		||||
 | 
			
		||||
            if (itemType != null)
 | 
			
		||||
                queryString["it"] = itemType;
 | 
			
		||||
            
 | 
			
		||||
            if(dataFilter != null)
 | 
			
		||||
                queryString["df"] =  dataFilter.ToString(Formatting.None);
 | 
			
		||||
 | 
			
		||||
            if (dataFilter != null)
 | 
			
		||||
                queryString["df"] = dataFilter.ToString(Formatting.None);
 | 
			
		||||
 | 
			
		||||
            resourceUri = (queryString.Count > 0 ? $"{resourceUri}?" : resourceUri) + queryString;
 | 
			
		||||
 | 
			
		||||
@@ -195,31 +201,34 @@ namespace FarmmapsApi.Services
 | 
			
		||||
        {
 | 
			
		||||
            var jsonString = JsonConvert.SerializeObject(itemRequest);
 | 
			
		||||
 | 
			
		||||
            var content = new StringContent(jsonString,  Encoding.UTF8,MediaTypeNames.Application.Json);
 | 
			
		||||
            var response = await _httpClient.PostAsync(ResourceEndpoints.ITEMS_CREATE_RESOURCE, 
 | 
			
		||||
            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 resourceUri = string.Format(ResourceEndpoints.ITEMS_RESOURCE, 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 response = await _httpClient.PostAsync(ResourceEndpoints.ITEMS_DELETE_RESOURCE, content);
 | 
			
		||||
            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);
 | 
			
		||||
@@ -227,10 +236,11 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        public async Task DownloadItemAsync(string itemCode, string filePath)
 | 
			
		||||
        {
 | 
			
		||||
            var resourceUri = string.Format(ResourceEndpoints.ITEMS_DOWNLOAD_RESOURCE, itemCode);
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
            if (response.IsSuccessStatusCode)
 | 
			
		||||
            {
 | 
			
		||||
                await using Stream streamToReadFrom = await response.Content.ReadAsStreamAsync();
 | 
			
		||||
                await using Stream streamToWriteTo = File.Open(filePath, FileMode.Create);
 | 
			
		||||
@@ -238,30 +248,32 @@ namespace FarmmapsApi.Services
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw new FileNotFoundException(response.ReasonPhrase);   
 | 
			
		||||
                throw new FileNotFoundException(response.ReasonPhrase);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<string> QueueTaskAsync(string itemCode, TaskRequest taskRequest)
 | 
			
		||||
        {
 | 
			
		||||
            var resourceUri = string.Format(ResourceEndpoints.ITEMTASK_REQUEST_RESOURCE, itemCode);
 | 
			
		||||
            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 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 resourceUri = string.Format(ResourceEndpoints.ITEMTASKS_RESOURCE, itemCode);
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMTASKS_RESOURCE}";
 | 
			
		||||
            var resourceUri = string.Format(url, itemCode);
 | 
			
		||||
            var response = await _httpClient.GetAsync(resourceUri);
 | 
			
		||||
 | 
			
		||||
            if (!response.IsSuccessStatusCode)
 | 
			
		||||
@@ -273,7 +285,8 @@ namespace FarmmapsApi.Services
 | 
			
		||||
 | 
			
		||||
        public async Task<ItemTaskStatus> GetTaskStatusAsync(string itemCode, string itemTaskCode)
 | 
			
		||||
        {
 | 
			
		||||
            var resourceUri = string.Format(ResourceEndpoints.ITEMTASK_RESOURCE, itemCode, itemTaskCode);
 | 
			
		||||
            var url = $"{_configuration.BasePath}/{ResourceEndpoints.ITEMTASK_RESOURCE}";
 | 
			
		||||
            var resourceUri = string.Format(url, itemCode, itemTaskCode);
 | 
			
		||||
            var response = await _httpClient.GetAsync(resourceUri);
 | 
			
		||||
 | 
			
		||||
            if (!response.IsSuccessStatusCode)
 | 
			
		||||
@@ -282,5 +295,85 @@ namespace FarmmapsApi.Services
 | 
			
		||||
            var jsonString = await response.Content.ReadAsStringAsync();
 | 
			
		||||
            return JsonConvert.DeserializeObject<ItemTaskStatus>(jsonString);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Experimental
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="filePath"></param>
 | 
			
		||||
        /// <param name="parentItemCode"></param>
 | 
			
		||||
        /// <param name="uploadCallback"></param>
 | 
			
		||||
        /// <returns></returns>
 | 
			
		||||
        /// <exception cref="FileNotFoundException"></exception>
 | 
			
		||||
        public async Task<Uri> UploadFile(string filePath, string parentItemCode, Action<IUploadProgress> uploadCallback)
 | 
			
		||||
        {
 | 
			
		||||
            if (!File.Exists(filePath))
 | 
			
		||||
                throw new FileNotFoundException($"File not found {filePath}");
 | 
			
		||||
            
 | 
			
		||||
            var mimeTypes = new MimeTypes();
 | 
			
		||||
            var mimeType = mimeTypes.GetMimeTypeFromFile(filePath);
 | 
			
		||||
            
 | 
			
		||||
            await using var uploadStream = new FileStream(filePath, FileMode.OpenOrCreate);
 | 
			
		||||
            
 | 
			
		||||
            var request = new FileRequest()
 | 
			
		||||
            {
 | 
			
		||||
                Name = Path.GetFileName(filePath),
 | 
			
		||||
                ParentCode = parentItemCode,
 | 
			
		||||
                Size = uploadStream.Length
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            Uri uploadIdentifierUri = null;
 | 
			
		||||
            using var httpClient = CreateConfigurableHttpClient(_httpClient);
 | 
			
		||||
            var farmmapsUploader = new FarmmapsUploader(httpClient, uploadStream, request, mimeType.ToString());
 | 
			
		||||
            
 | 
			
		||||
            farmmapsUploader.ProgressChanged += uploadCallback;
 | 
			
		||||
            farmmapsUploader.UploadSessionData += data => uploadIdentifierUri = data.UploadUri;
 | 
			
		||||
            
 | 
			
		||||
            await farmmapsUploader.UploadAsync();
 | 
			
		||||
 | 
			
		||||
            return uploadIdentifierUri;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <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);
 | 
			
		||||
            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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										160
									
								
								FarmmapsApi/Services/FarmmapsUploader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								FarmmapsApi/Services/FarmmapsUploader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Net.Mime;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using FarmmapsApi.Models;
 | 
			
		||||
using Google.Apis.Http;
 | 
			
		||||
using Google.Apis.Json;
 | 
			
		||||
using Google.Apis.Requests;
 | 
			
		||||
using Google.Apis.Upload;
 | 
			
		||||
using Google.Apis.Util;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
 | 
			
		||||
namespace FarmmapsApi.Services
 | 
			
		||||
{
 | 
			
		||||
    public class FarmmapsUploader : ResumableUpload
 | 
			
		||||
    {
 | 
			
		||||
        /// <summary>Payload description headers, describing the content itself.</summary>
 | 
			
		||||
        private const string PayloadContentTypeHeader = "X-Upload-Content-Type";
 | 
			
		||||
 | 
			
		||||
        /// <summary>Payload description headers, describing the content itself.</summary>
 | 
			
		||||
        private const string PayloadContentLengthHeader = "X-Upload-Content-Length";
 | 
			
		||||
 | 
			
		||||
        private const int UnknownSize = -1;
 | 
			
		||||
 | 
			
		||||
        /// <summary>Gets or sets the service.</summary>
 | 
			
		||||
        private HttpClient HttpClient { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Gets or sets the path of the method (combined with
 | 
			
		||||
        /// <see cref="Google.Apis.Services.IClientService.BaseUri"/>) to produce 
 | 
			
		||||
        /// absolute Uri. 
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private string Path { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>Gets or sets the HTTP method of this upload (used to initialize the upload).</summary>
 | 
			
		||||
        private string HttpMethod { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>Gets or sets the stream's Content-Type.</summary>
 | 
			
		||||
        private string ContentType { get; }
 | 
			
		||||
 | 
			
		||||
        /// <summary>Gets or sets the body of this request.</summary>
 | 
			
		||||
        private FileRequest Body { get; }
 | 
			
		||||
 | 
			
		||||
        private long _streamLength;
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Create a resumable upload instance with the required parameters.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="contentStream">The stream containing the content to upload.</param>
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// Caller is responsible for maintaining the <paramref name="contentStream"/> open until the upload is 
 | 
			
		||||
        /// completed.
 | 
			
		||||
        /// Caller is responsible for closing the <paramref name="contentStream"/>.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        public FarmmapsUploader(ConfigurableHttpClient httpClient, Stream contentStream, FileRequest body, string contentType)
 | 
			
		||||
            : base(contentStream,
 | 
			
		||||
                new ResumableUploadOptions
 | 
			
		||||
                {
 | 
			
		||||
                    HttpClient = httpClient,
 | 
			
		||||
                    Serializer = new NewtonsoftJsonSerializer(),
 | 
			
		||||
                    ServiceName = "FarmMaps"
 | 
			
		||||
                })
 | 
			
		||||
        {
 | 
			
		||||
            httpClient.ThrowIfNull(nameof(httpClient));
 | 
			
		||||
            contentStream.ThrowIfNull(nameof(contentStream));
 | 
			
		||||
            
 | 
			
		||||
            _streamLength = ContentStream.CanSeek ? ContentStream.Length : UnknownSize;
 | 
			
		||||
            Body = body;
 | 
			
		||||
            Path = "api/v1/file";
 | 
			
		||||
            HttpClient = httpClient;
 | 
			
		||||
            HttpMethod = HttpConsts.Post;
 | 
			
		||||
            ContentType = contentType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <inheritdoc/>
 | 
			
		||||
        public override async Task<Uri> InitiateSessionAsync(CancellationToken cancellationToken = default)
 | 
			
		||||
        {
 | 
			
		||||
            HttpRequestMessage request = CreateInitializeRequest();
 | 
			
		||||
            Options?.ModifySessionInitiationRequest?.Invoke(request);
 | 
			
		||||
            var response = await HttpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            if (!response.IsSuccessStatusCode)
 | 
			
		||||
            {
 | 
			
		||||
                throw await ExceptionForResponseAsync(response).ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            return response.Headers.Location;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>Creates a request to initialize a request.</summary>
 | 
			
		||||
        private HttpRequestMessage CreateInitializeRequest()
 | 
			
		||||
        {
 | 
			
		||||
            var baseAddres = HttpClient.BaseAddress;
 | 
			
		||||
            var uri = new Uri($"{baseAddres.Scheme}://{baseAddres.Host}:{baseAddres.Port}");
 | 
			
		||||
            var builder = new RequestBuilder()
 | 
			
		||||
            {
 | 
			
		||||
                BaseUri = uri,
 | 
			
		||||
                Path = Path,
 | 
			
		||||
                Method = HttpMethod,
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            SetAllPropertyValues(builder);
 | 
			
		||||
 | 
			
		||||
            HttpRequestMessage request = builder.CreateRequest();
 | 
			
		||||
            if (ContentType != null)
 | 
			
		||||
            {
 | 
			
		||||
                request.Headers.Add(PayloadContentTypeHeader, ContentType);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // if the length is unknown at the time of this request, omit "X-Upload-Content-Length" header
 | 
			
		||||
            if (ContentStream.CanSeek)
 | 
			
		||||
            {
 | 
			
		||||
                request.Headers.Add(PayloadContentLengthHeader, _streamLength.ToString());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var jsonText = JsonConvert.SerializeObject(Body);
 | 
			
		||||
            request.Content = new StringContent(jsonText, Encoding.UTF8, MediaTypeNames.Application.Json);
 | 
			
		||||
 | 
			
		||||
            return request;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Reflectively enumerate the properties of this object looking for all properties containing the 
 | 
			
		||||
        /// RequestParameterAttribute and copy their values into the request builder.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        private void SetAllPropertyValues(RequestBuilder requestBuilder)
 | 
			
		||||
        {
 | 
			
		||||
            Type myType = this.GetType();
 | 
			
		||||
            var properties = myType.GetProperties();
 | 
			
		||||
 | 
			
		||||
            foreach (var property in properties)
 | 
			
		||||
            {
 | 
			
		||||
                var attribute = property.GetCustomAttribute<RequestParameterAttribute>();
 | 
			
		||||
                if (attribute != null)
 | 
			
		||||
                {
 | 
			
		||||
                    string name = attribute.Name ?? property.Name.ToLower();
 | 
			
		||||
                    object value = property.GetValue(this, null);
 | 
			
		||||
                    if (value != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!(value is string) && value is IEnumerable valueAsEnumerable)
 | 
			
		||||
                        {
 | 
			
		||||
                            foreach (var elem in valueAsEnumerable)
 | 
			
		||||
                            {
 | 
			
		||||
                                requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(elem));
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // Otherwise just convert it to a string.
 | 
			
		||||
                            requestBuilder.AddParameter(attribute.Type, name, Utilities.ConvertToString(value));
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								FarmmapsApiSamples/Data/Belgie.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								FarmmapsApiSamples/Data/Belgie.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								FarmmapsApiSamples/Data/Scan_1_20190605.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								FarmmapsApiSamples/Data/Scan_1_20190605.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -9,6 +9,9 @@
 | 
			
		||||
      <None Update="appsettings.json">
 | 
			
		||||
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
			
		||||
      </None>
 | 
			
		||||
      <None Update="Data\**\*">
 | 
			
		||||
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
 | 
			
		||||
      </None>
 | 
			
		||||
    </ItemGroup>
 | 
			
		||||
 | 
			
		||||
    <ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using FarmmapsApi.Models;
 | 
			
		||||
using FarmmapsApi.Services;
 | 
			
		||||
using Google.Apis.Upload;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Newtonsoft.Json.Linq;
 | 
			
		||||
using static FarmmapsApi.Extensions;
 | 
			
		||||
@@ -12,6 +15,8 @@ namespace FarmmapsApiSamples
 | 
			
		||||
    public class NbsApp : IApp
 | 
			
		||||
    {
 | 
			
		||||
        private const string USERINPUT_ITEMTYPE = "vnd.farmmaps.itemtype.user.input";
 | 
			
		||||
        private const string GEOTIFF_ITEMTYPE = "vnd.farmmaps.itemtype.geotiff";
 | 
			
		||||
        private const string CROPFIELD_ITEMTYPE = "vnd.farmmaps.itemtype.cropfield";
 | 
			
		||||
        private const string VRANBS_TASK = "vnd.farmmaps.task.vranbs";
 | 
			
		||||
        
 | 
			
		||||
        private readonly ILogger<NbsApp> _logger;
 | 
			
		||||
@@ -41,14 +46,33 @@ namespace FarmmapsApiSamples
 | 
			
		||||
                _logger.LogInformation("Authenticated client credentials");
 | 
			
		||||
 | 
			
		||||
                var roots = await _farmmapsApiService.GetCurrentUserRootsAsync();
 | 
			
		||||
                var myDriveRoot = roots.SingleOrDefault(r => r.Name == "My drive");
 | 
			
		||||
 | 
			
		||||
                if (myDriveRoot != null)
 | 
			
		||||
                
 | 
			
		||||
                // upload data to Uploaded
 | 
			
		||||
                var uploadedRoot = roots.SingleOrDefault(r => r.Name == "Uploaded");
 | 
			
		||||
                if (uploadedRoot != null)
 | 
			
		||||
                {
 | 
			
		||||
                    var cropfieldItem = await GetOrCreateCropfieldItem(myDriveRoot.Code);
 | 
			
		||||
                    var targetN = await CalculateTargetN(cropfieldItem, 60);
 | 
			
		||||
                    await _farmmapsApiService.UploadFile(Path.Combine("Data", "Scan_1_20190605.zip"), uploadedRoot.Code,
 | 
			
		||||
                        progress =>
 | 
			
		||||
                        {
 | 
			
		||||
                            _logger.LogInformation($"Status: {progress.Status} - BytesSent: {progress.BytesSent}");
 | 
			
		||||
                            if(progress.Status == UploadStatus.Failed)
 | 
			
		||||
                                _logger.LogError($"Uploading failed {progress.Exception.Message}");
 | 
			
		||||
                        });
 | 
			
		||||
                    
 | 
			
		||||
                    _logger.LogInformation($"TargetN: {targetN}");
 | 
			
		||||
                    // need to transform shape data to geotiff
 | 
			
		||||
 | 
			
		||||
                    var myDriveRoot = roots.SingleOrDefault(r => r.Name == "My drive");
 | 
			
		||||
                    if (myDriveRoot != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        var cropfieldItem = await GetOrCreateCropfieldItem(myDriveRoot.Code);
 | 
			
		||||
                    
 | 
			
		||||
                        _logger.LogInformation($"Calculating targetN with targetYield: {60}");
 | 
			
		||||
                        var targetN = await CalculateTargetN(cropfieldItem, 60);
 | 
			
		||||
                        _logger.LogInformation($"TargetN: {targetN}");
 | 
			
		||||
                    
 | 
			
		||||
                        _logger.LogInformation("Calculating nitrogen map");
 | 
			
		||||
//                    var nitrogenMapItem = CalculateNitrogenMap(cropfieldItem,, targetN);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
@@ -60,7 +84,7 @@ namespace FarmmapsApiSamples
 | 
			
		||||
        private async Task<Item> GetOrCreateCropfieldItem(string parentItemCode)
 | 
			
		||||
        {
 | 
			
		||||
            var cropfieldItems = await
 | 
			
		||||
                _farmmapsApiService.GetItemChildrenAsync(parentItemCode, "vnd.farmmaps.itemtype.cropfield");
 | 
			
		||||
                _farmmapsApiService.GetItemChildrenAsync(parentItemCode,CROPFIELD_ITEMTYPE);
 | 
			
		||||
 | 
			
		||||
            if (cropfieldItems.Count > 0) 
 | 
			
		||||
                return cropfieldItems[0];
 | 
			
		||||
@@ -70,18 +94,24 @@ namespace FarmmapsApiSamples
 | 
			
		||||
            {
 | 
			
		||||
                ParentCode = parentItemCode,
 | 
			
		||||
                ItemType = "vnd.farmmaps.itemtype.cropfield",
 | 
			
		||||
                Name = "cropfield for VRA",
 | 
			
		||||
                Name = "Cropfield for VRA",
 | 
			
		||||
                DataDate = currentYear,
 | 
			
		||||
                DataEndDate = currentYear.AddYears(1),
 | 
			
		||||
                Data = JObject.FromObject(new
 | 
			
		||||
                    {startDate = currentYear, endDate = currentYear.AddYears(1)}),
 | 
			
		||||
                    {startDate = currentYear, endDate = currentYear.AddMonths(3)}),
 | 
			
		||||
                Geometry = JObject.Parse(
 | 
			
		||||
                    @"{""type"":""Polygon"",""coordinates"":[[[6.09942873984307,53.070025028087],[6.09992507404607,53.0705617890585],[6.10036959220086,53.0710679529031],[6.10065149010421,53.0714062774307],[6.10087493644271,53.0716712354474],[6.10091082982487,53.0716936039203],[6.10165087441291,53.0712041549161],[6.10204994718318,53.0709349338005],[6.10263143118855,53.0705789370018],[6.10311578125011,53.0702657538294],[6.10331686552072,53.0701314102389],[6.103326530575,53.070119463569],[6.10309137950343,53.0699829669055],[6.10184241586523,53.0692902201371],[6.10168497998891,53.0691984306747],[6.10092987659869,53.0694894453514],[6.09942873984307,53.070025028087]]]}")
 | 
			
		||||
                    @"{ ""type"": ""Polygon"", ""coordinates"": [ [ [ 3.40843828875524, 50.638966444680605 ], [ 3.408953272886064, 50.639197789621612 ], [ 3.409242951459603, 50.639469958681836 ], [ 3.409328782148028, 50.639612846807708 ], [ 3.409457528180712, 50.639789755314411 ], [ 3.409639918393741, 50.640014292074966 ], [ 3.409833037442765, 50.640211611372706 ], [ 3.410069071836049, 50.640395321698435 ], [ 3.410380208081761, 50.640572227259661 ], [ 3.410605513638958, 50.640715112034222 ], [ 3.411925160474145, 50.641177783561204 ], [ 3.411935889310142, 50.640728720085136 ], [ 3.412590348309737, 50.63948356709389 ], [ 3.413244807309242, 50.638224772339846 ], [ 3.413400375432099, 50.637901562841307 ], [ 3.413539850300779, 50.637449065809889 ], [ 3.413475477284437, 50.637418445552932 ], [ 3.40999396998362, 50.637449065810451 ], [ 3.409940325803365, 50.638102293212661 ], [ 3.409575545377398, 50.638483338338325 ], [ 3.409060561246574, 50.638707881340494 ], [ 3.40843828875524, 50.638966444680605 ] ] ] }")
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Calculates TargetN, makes the assumption the cropfield and user.input(targetn) item have the same parent
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <param name="cropfieldItem">The cropfield to base the calculations on</param>
 | 
			
		||||
        /// <param name="targetYield">The target yield input for the TargetN calculation</param>
 | 
			
		||||
        /// <returns>The TargetN</returns>
 | 
			
		||||
        private async Task<double> CalculateTargetN(Item cropfieldItem, int targetYield)
 | 
			
		||||
        {
 | 
			
		||||
            var targetNItems = await
 | 
			
		||||
@@ -99,8 +129,6 @@ namespace FarmmapsApiSamples
 | 
			
		||||
                targetNItem = targetNItems[0];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _logger.LogInformation($"Calculating targetN with targetYield: {targetYield}");
 | 
			
		||||
            
 | 
			
		||||
            var nbsTargetNRequest = new TaskRequest {TaskType = VRANBS_TASK};
 | 
			
		||||
            nbsTargetNRequest.attributes["operation"] = "targetn";
 | 
			
		||||
            nbsTargetNRequest.attributes["inputCode"] = targetNItem.Code;
 | 
			
		||||
@@ -111,19 +139,63 @@ namespace FarmmapsApiSamples
 | 
			
		||||
            
 | 
			
		||||
            await PollTask(TimeSpan.FromSeconds(3), async (tokenSource) =>
 | 
			
		||||
            {
 | 
			
		||||
                var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
			
		||||
 | 
			
		||||
                if (itemTask.State != ItemTaskState.Processing && itemTask.State != ItemTaskState.Scheduled)
 | 
			
		||||
                var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
			
		||||
                if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled)
 | 
			
		||||
                    tokenSource.Cancel();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
			
		||||
            if(itemTask.State == ItemTaskState.Error)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Something went wrong with task execution: {itemTask.Message}");
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var item = await _farmmapsApiService.GetItemAsync(targetNItem.Code);
 | 
			
		||||
            if (item.Data.ContainsKey("TargetN"))
 | 
			
		||||
                return item.Data["TargetN"].Value<double>();
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<Item> CalculateNitrogenMap(Item cropfieldItem, Item inputItem, double targetN)
 | 
			
		||||
        {
 | 
			
		||||
            var nbsNitrogenRequest = new TaskRequest {TaskType = VRANBS_TASK};
 | 
			
		||||
            nbsNitrogenRequest.attributes["operation"] = "nitrogen";
 | 
			
		||||
            nbsNitrogenRequest.attributes["inputCode"] = inputItem.Code;
 | 
			
		||||
            nbsNitrogenRequest.attributes["inputType"] = "irmi";
 | 
			
		||||
            nbsNitrogenRequest.attributes["targetN"] = targetN.ToString(CultureInfo.InvariantCulture);
 | 
			
		||||
            
 | 
			
		||||
            string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, nbsNitrogenRequest);
 | 
			
		||||
            
 | 
			
		||||
            await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) =>
 | 
			
		||||
            {
 | 
			
		||||
                var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
			
		||||
                if (itemTaskStatus.State != ItemTaskState.Processing && itemTaskStatus.State != ItemTaskState.Scheduled)
 | 
			
		||||
                    tokenSource.Cancel();
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode);
 | 
			
		||||
            if(itemTask.State == ItemTaskState.Error)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Something went wrong with task execution: {itemTask.Message}");
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            var geotiffItems = await
 | 
			
		||||
                _farmmapsApiService.GetItemChildrenAsync(cropfieldItem.Code, GEOTIFF_ITEMTYPE);
 | 
			
		||||
 | 
			
		||||
            // how to uniquely know which item is really created!?
 | 
			
		||||
            var nitrogenItem = geotiffItems.SingleOrDefault(i => i.Name.Contains("nitrogen"));
 | 
			
		||||
            if (nitrogenItem == null)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError("Could not find the nitrogen geotiff child item under cropfield");
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return nitrogenItem;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ItemRequest CreateTargetNItemRequest(string parentItemCode)
 | 
			
		||||
        {
 | 
			
		||||
            return new ItemRequest()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "Authority": "https://accounts.farmmaps.awtest.nl/",
 | 
			
		||||
  "Endpoint": "https://farmmaps.awtest.nl/api/v1/",
 | 
			
		||||
  "Endpoint": "http://localhost:8083",
 | 
			
		||||
  "BasePath": "api/v1",
 | 
			
		||||
  "DiscoveryEndpointUrl": "https://accounts.farmmaps.awtest.nl/.well-known/openid-configuration",
 | 
			
		||||
  "RedirectUri": "http://example.nl/api",
 | 
			
		||||
  "ClientId": "",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user