From 207545113a0f8c9ad94f2a1963603b0f6748c144 Mon Sep 17 00:00:00 2001 From: "sushi.at" Date: Tue, 19 Dec 2023 18:48:15 +0000 Subject: [PATCH 1/2] Added support for notifications --- OpenSky.Agent.Simulator/OpenAPIs/swagger.cs | 1182 +++++++++++++++-- OpenSky.Agent.Simulator/OpenAPIs/swagger.json | 623 +++++++++ .../Views/Models/StartupViewModel.cs | 279 ++-- 3 files changed, 1893 insertions(+), 191 deletions(-) diff --git a/OpenSky.Agent.Simulator/OpenAPIs/swagger.cs b/OpenSky.Agent.Simulator/OpenAPIs/swagger.cs index ad448bb..61ad9e4 100644 --- a/OpenSky.Agent.Simulator/OpenAPIs/swagger.cs +++ b/OpenSky.Agent.Simulator/OpenAPIs/swagger.cs @@ -408,6 +408,92 @@ public virtual async System.Threading.Tasks.Task GetProfil } } + /// + /// Gets the username list of all OpenSky users. + /// + /// + /// sushi.at, 18/12/2023. + /// + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetUserNamesAsync() + { + return GetUserNamesAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Gets the username list of all OpenSky users. + /// + /// + /// sushi.at, 18/12/2023. + /// + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetUserNamesAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Account/usernames"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + /// /// Get the list of all OpenSky users. /// @@ -8389,31 +8475,33 @@ public virtual async System.Threading.Tasks.Task - /// Get world statistics overview. + /// Add a new notification. /// /// - /// sushi.at, 02/07/2021. + /// sushi.at, 15/12/2023. /// + /// The add notification model. /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task GetWorldStatisticsOverviewAsync() + public virtual System.Threading.Tasks.Task AddNotificationAsync(AddNotification body) { - return GetWorldStatisticsOverviewAsync(System.Threading.CancellationToken.None); + return AddNotificationAsync(body, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Get world statistics overview. + /// Add a new notification. /// /// - /// sushi.at, 02/07/2021. + /// sushi.at, 15/12/2023. /// + /// The add notification model. /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetWorldStatisticsOverviewAsync(System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task AddNotificationAsync(AddNotification body, System.Threading.CancellationToken cancellationToken) { var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/WorldStatistics"); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification"); var client_ = _httpClient; var disposeClient_ = false; @@ -8421,7 +8509,11 @@ public virtual async System.Threading.Tasks.Task(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -8475,37 +8567,38 @@ public virtual async System.Threading.Tasks.Task - /// Manually request to populate an airport and return info text results. + /// Get notifications for specified target. /// /// - /// sushi.at, 05/07/2021. + /// sushi.at, 18/12/2023. /// - /// The icao of the airport to populate. + /// The target for the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All /// Success /// A server side error occurred. - public virtual System.Threading.Tasks.Task PopulateAirportWithAircraftAsync(string icao) + public virtual System.Threading.Tasks.Task GetNotificationsAsync(NotificationTarget? target) { - return PopulateAirportWithAircraftAsync(icao, System.Threading.CancellationToken.None); + return GetNotificationsAsync(target, System.Threading.CancellationToken.None); } /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// - /// Manually request to populate an airport and return info text results. + /// Get notifications for specified target. /// /// - /// sushi.at, 05/07/2021. + /// sushi.at, 18/12/2023. /// - /// The icao of the airport to populate. + /// The target for the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All /// Success /// A server side error occurred. - public virtual async System.Threading.Tasks.Task PopulateAirportWithAircraftAsync(string icao, System.Threading.CancellationToken cancellationToken) + public virtual async System.Threading.Tasks.Task GetNotificationsAsync(NotificationTarget? target, System.Threading.CancellationToken cancellationToken) { - if (icao == null) - throw new System.ArgumentNullException("icao"); - var urlBuilder_ = new System.Text.StringBuilder(); - urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/WorldStatistics/populateAircraft/{icao}"); - urlBuilder_.Replace("{icao}", System.Uri.EscapeDataString(ConvertToString(icao, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification?"); + if (target != null) + { + urlBuilder_.Append(System.Uri.EscapeDataString("target") + "=").Append(System.Uri.EscapeDataString(ConvertToString(target, System.Globalization.CultureInfo.InvariantCulture))).Append("&"); + } + urlBuilder_.Length--; var client_ = _httpClient; var disposeClient_ = false; @@ -8513,8 +8606,7 @@ public virtual async System.Threading.Tasks.Task PopulateAirp { using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) { - request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); - request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Method = new System.Net.Http.HttpMethod("GET"); request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); PrepareRequest(client_, request_, urlBuilder_); @@ -8540,7 +8632,7 @@ public virtual async System.Threading.Tasks.Task PopulateAirp var status_ = (int)response_.StatusCode; if (status_ == 200) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -8567,102 +8659,651 @@ public virtual async System.Threading.Tasks.Task PopulateAirp } } - protected struct ObjectResponseResult + /// + /// Confirm successful pickup of a notification for the specified target. + /// + /// + /// sushi.at, 18/12/2023. + /// + /// Identifier for the notification. + /// The target of the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task ConfirmNotificationPickupAsync(System.Guid notificationID, NotificationTarget target) { - public ObjectResponseResult(T responseObject, string responseText) - { - this.Object = responseObject; - this.Text = responseText; - } - - public T Object { get; } - - public string Text { get; } + return ConfirmNotificationPickupAsync(notificationID, target, System.Threading.CancellationToken.None); } - public bool ReadResponseAsString { get; set; } - - protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Confirm successful pickup of a notification for the specified target. + /// + /// + /// sushi.at, 18/12/2023. + /// + /// Identifier for the notification. + /// The target of the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task ConfirmNotificationPickupAsync(System.Guid notificationID, NotificationTarget target, System.Threading.CancellationToken cancellationToken) { - if (response == null || response.Content == null) - { - return new ObjectResponseResult(default(T), string.Empty); - } + if (notificationID == null) + throw new System.ArgumentNullException("notificationID"); - if (ReadResponseAsString) - { - var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - try - { - var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); - return new ObjectResponseResult(typedBody, responseText); - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); - } - } - else - { - try - { - using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - using (var streamReader = new System.IO.StreamReader(responseStream)) - using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) - { - var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); - var typedBody = serializer.Deserialize(jsonTextReader); - return new ObjectResponseResult(typedBody, string.Empty); - } - } - catch (Newtonsoft.Json.JsonException exception) - { - var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; - throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); - } - } - } + if (target == null) + throw new System.ArgumentNullException("target"); - private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) - { - if (value == null) - { - return ""; - } + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification/{notificationID}/{target}"); + urlBuilder_.Replace("{notificationID}", System.Uri.EscapeDataString(ConvertToString(notificationID, System.Globalization.CultureInfo.InvariantCulture))); + urlBuilder_.Replace("{target}", System.Uri.EscapeDataString(ConvertToString(target, System.Globalization.CultureInfo.InvariantCulture))); - if (value is System.Enum) + var client_ = _httpClient; + var disposeClient_ = false; + try { - var name = System.Enum.GetName(value.GetType(), value); - if (name != null) + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) { - var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); - if (field != null) + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try { - var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) - as System.Runtime.Serialization.EnumMemberAttribute; - if (attribute != null) + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) { - return attribute.Value != null ? attribute.Value : name; + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; } - } - var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); - return converted == null ? string.Empty : converted; + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } } } - else if (value is bool) - { - return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); - } - else if (value is byte[]) + finally { - return System.Convert.ToBase64String((byte[]) value); + if (disposeClient_) + client_.Dispose(); } - else if (value.GetType().IsArray) - { - var array = System.Linq.Enumerable.OfType((System.Array) value); - return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + /// + /// Delete specified notification group. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Identifier for the grouping. + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task DeleteNotificationAsync(System.Guid groupingID) + { + return DeleteNotificationAsync(groupingID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Delete specified notification group. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Identifier for the grouping. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task DeleteNotificationAsync(System.Guid groupingID, System.Threading.CancellationToken cancellationToken) + { + if (groupingID == null) + throw new System.ArgumentNullException("groupingID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification/{groupingID}"); + urlBuilder_.Replace("{groupingID}", System.Uri.EscapeDataString(ConvertToString(groupingID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Method = new System.Net.Http.HttpMethod("DELETE"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Active fallback to email NOW for specified notification. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Identifier for the grouping. + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task FallbackNotificationToEmailNowAsync(System.Guid groupingID) + { + return FallbackNotificationToEmailNowAsync(groupingID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Active fallback to email NOW for specified notification. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Identifier for the grouping. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task FallbackNotificationToEmailNowAsync(System.Guid groupingID, System.Threading.CancellationToken cancellationToken) + { + if (groupingID == null) + throw new System.ArgumentNullException("groupingID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification/fallbackEmailNow/{groupingID}"); + urlBuilder_.Replace("{groupingID}", System.Uri.EscapeDataString(ConvertToString(groupingID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); + request_.Method = new System.Net.Http.HttpMethod("PUT"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get all currently active notifications. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetAllNotificationsAsync() + { + return GetAllNotificationsAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get all currently active notifications. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetAllNotificationsAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/Notification/all"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Get world statistics overview. + /// + /// + /// sushi.at, 02/07/2021. + /// + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task GetWorldStatisticsOverviewAsync() + { + return GetWorldStatisticsOverviewAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Get world statistics overview. + /// + /// + /// sushi.at, 02/07/2021. + /// + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task GetWorldStatisticsOverviewAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/WorldStatistics"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// + /// Manually request to populate an airport and return info text results. + /// + /// + /// sushi.at, 05/07/2021. + /// + /// The icao of the airport to populate. + /// Success + /// A server side error occurred. + public virtual System.Threading.Tasks.Task PopulateAirportWithAircraftAsync(string icao) + { + return PopulateAirportWithAircraftAsync(icao, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// + /// Manually request to populate an airport and return info text results. + /// + /// + /// sushi.at, 05/07/2021. + /// + /// The icao of the airport to populate. + /// Success + /// A server side error occurred. + public virtual async System.Threading.Tasks.Task PopulateAirportWithAircraftAsync(string icao, System.Threading.CancellationToken cancellationToken) + { + if (icao == null) + throw new System.ArgumentNullException("icao"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/WorldStatistics/populateAircraft/{icao}"); + urlBuilder_.Replace("{icao}", System.Uri.EscapeDataString(ConvertToString(icao, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = await CreateHttpRequestMessageAsync(cancellationToken).ConfigureAwait(false)) + { + request_.Content = new System.Net.Http.StringContent(string.Empty, System.Text.Encoding.UTF8, "text/plain"); + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("text/plain")); + + PrepareRequest(client_, request_, urlBuilder_); + + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers, System.Threading.CancellationToken cancellationToken) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return ""; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + return converted == null ? string.Empty : converted; + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[]) value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array) value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); } var result = System.Convert.ToString(value, cultureInfo); @@ -8798,6 +9439,63 @@ public partial class AccountOverviewApiResponse } + /// + /// Add notification model. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class AddNotification + { + /// + /// Optional: Gets or sets the number of seconds after which to auto-dismiss the notification (or NULL for no + ///
timeout) + ///
+ [Newtonsoft.Json.JsonProperty("displayTimeout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? DisplayTimeout { get; set; } + + /// + /// Optional: Gets or sets the number of hours after which the message gets sent via email if no client picked it up. + /// + [Newtonsoft.Json.JsonProperty("emailFallbackHours", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? EmailFallbackHours { get; set; } + + /// + /// Optional: Gets or sets the expiration in minutes. + /// + [Newtonsoft.Json.JsonProperty("expiresInMinutes", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? ExpiresInMinutes { get; set; } + + /// + /// Gets or sets the message. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.StringLength(500)] + public string Message { get; set; } + + [Newtonsoft.Json.JsonProperty("recipientType", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationRecipient RecipientType { get; set; } + + /// + /// Gets or sets the recipient username (only if recipient type is user). + /// + [Newtonsoft.Json.JsonProperty("recipientUserName", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(256)] + public string RecipientUserName { get; set; } + + /// + /// Gets or sets a value indicating whether to send the notification as "OpenSky System" + /// + [Newtonsoft.Json.JsonProperty("sendAsSystem", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool SendAsSystem { get; set; } + + [Newtonsoft.Json.JsonProperty("style", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationStyle Style { get; set; } + + [Newtonsoft.Json.JsonProperty("target", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationTarget Target { get; set; } + + } + /// /// Aircraft model. /// @@ -10282,6 +10980,83 @@ public partial class ChangePassword } + /// + /// Client/Agent notification model. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class ClientNotification + { + /// + /// Optional: The number of seconds after which to auto-dismiss the notification (or NULL for no + ///
timeout) + ///
+ [Newtonsoft.Json.JsonProperty("displayTimeout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? DisplayTimeout { get; set; } + + /// + /// Gets or sets the identifier of the notification. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid Id { get; set; } + + /// + /// Gets or sets the message. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [System.ComponentModel.DataAnnotations.StringLength(500)] + public string Message { get; set; } + + /// + /// Gets or sets the sender (or NULL for OpenSky System). + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.StringLength(256)] + public string Sender { get; set; } + + [Newtonsoft.Json.JsonProperty("style", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationStyle Style { get; set; } + + } + + /// + /// API standard response model. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class ClientNotificationIEnumerableApiResponse + { + /// + /// Gets or sets the embedded data of type T. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Data { get; set; } + + /// + /// Gets or sets the error details (NULL if no error). + /// + [Newtonsoft.Json.JsonProperty("errorDetails", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorDetails { get; set; } + + /// + /// Gets or sets a value indicating whether this response is reporting an error. + /// + [Newtonsoft.Json.JsonProperty("isError", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsError { get; set; } + + /// + /// Gets or sets the message. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } + + /// + /// Gets or sets the status. + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + } + /// /// Enum of two letter country codes according to ISO-3166. 1 = AF, 2 = AX, 3 = AL, 4 = DZ, 5 = AS, 6 = AD, 7 = AO, 8 = AI, 9 = AQ, 10 = AG, 11 = AR, 12 = AM, 13 = AW, 14 = AU, 15 = AT, 16 = AZ, 17 = BS, 18 = BH, 19 = BD, 20 = BB, 21 = BY, 22 = BE, 23 = BZ, 24 = BJ, 25 = BM, 26 = BT, 27 = BO, 28 = BQ, 29 = BA, 30 = BW, 31 = BV, 32 = BR, 33 = IO, 34 = BN, 35 = BG, 36 = BF, 37 = BI, 38 = CV, 39 = KH, 40 = CM, 41 = CA, 42 = KY, 43 = CF, 44 = TD, 45 = CL, 46 = CN, 47 = CX, 48 = CC, 49 = CO, 50 = KM, 51 = CG, 52 = CD, 53 = CK, 54 = CR, 55 = CI, 56 = HR, 57 = CU, 58 = CW, 59 = CY, 60 = CZ, 61 = DK, 62 = DJ, 63 = DM, 64 = DO, 65 = EC, 66 = EG, 67 = SV, 68 = GQ, 69 = ER, 70 = EE, 71 = ET, 72 = FK, 73 = FO, 74 = FJ, 75 = FI, 76 = FR, 77 = GF, 78 = PF, 79 = TF, 80 = GA, 81 = GM, 82 = GE, 83 = DE, 84 = GH, 85 = GI, 86 = GR, 87 = GL, 88 = GD, 89 = GP, 90 = GU, 91 = GT, 92 = GG, 93 = GN, 94 = GW, 95 = GY, 96 = HT, 97 = HM, 98 = VA, 99 = HN, 100 = HK, 101 = HU, 102 = IS, 103 = IN, 104 = ID, 105 = IR, 106 = IQ, 107 = IE, 108 = IM, 109 = IL, 110 = IT, 111 = JM, 112 = JP, 113 = JE, 114 = JO, 115 = KZ, 116 = KE, 117 = KI, 118 = KP, 119 = KR, 120 = KW, 121 = KG, 122 = LA, 123 = LV, 124 = LB, 125 = LS, 126 = LR, 127 = LY, 128 = LI, 129 = LT, 130 = LU, 131 = MO, 132 = MK, 133 = MG, 134 = MW, 135 = MY, 136 = MV, 137 = ML, 138 = MT, 139 = MH, 140 = MQ, 141 = MR, 142 = MU, 143 = YT, 144 = MX, 145 = FM, 146 = MD, 147 = MC, 148 = MN, 149 = ME, 150 = MS, 151 = MA, 152 = MZ, 153 = MM, 154 = NA, 155 = NR, 156 = NP, 157 = NL, 158 = NC, 159 = NZ, 160 = NI, 161 = NE, 162 = NG, 163 = NU, 164 = NF, 165 = MP, 166 = NO, 167 = OM, 168 = PK, 169 = PW, 170 = PS, 171 = PA, 172 = PG, 173 = PY, 174 = PE, 175 = PH, 176 = PN, 177 = PL, 178 = PT, 179 = PR, 180 = QA, 181 = RE, 182 = RO, 183 = RU, 184 = RW, 185 = BL, 186 = SH, 187 = KN, 188 = LC, 189 = MF, 190 = PM, 191 = VC, 192 = WS, 193 = SM, 194 = ST, 195 = SA, 196 = SN, 197 = RS, 198 = SC, 199 = SL, 200 = SG, 201 = SX, 202 = SK, 203 = SI, 204 = SB, 205 = SO, 206 = ZA, 207 = GS, 208 = SS, 209 = ES, 210 = LK, 211 = SD, 212 = SR, 213 = SJ, 214 = SZ, 215 = SE, 216 = CH, 217 = SY, 218 = TW, 219 = TJ, 220 = TZ, 221 = TH, 222 = TL, 223 = TG, 224 = TK, 225 = TO, 226 = TT, 227 = TN, 228 = TR, 229 = TM, 230 = TC, 231 = TV, 232 = UG, 233 = UA, 234 = AE, 235 = GB, 236 = US, 237 = UM, 238 = UY, 239 = UZ, 240 = VU, 241 = VE, 242 = VN, 243 = VG, 244 = VI, 245 = WF, 246 = EH, 247 = YE, 248 = ZM, 249 = ZW, 250 = XK /// @@ -12281,6 +13056,144 @@ public partial class GroundOperations } + /// + /// Grouped notification model. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class GroupedNotification + { + /// + /// Gets or sets the display timeout. + /// + [Newtonsoft.Json.JsonProperty("displayTimeout", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public int? DisplayTimeout { get; set; } + + /// + /// Gets or sets the Date/Time of the email fallback. + /// + [Newtonsoft.Json.JsonProperty("emailFallback", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.DateTimeOffset? EmailFallback { get; set; } + + /// + /// Gets or sets the Date/Time of the expiration. + /// + [Newtonsoft.Json.JsonProperty("expires", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.DateTimeOffset? Expires { get; set; } + + /// + /// Gets or sets the identifier of the grouping. + /// + [Newtonsoft.Json.JsonProperty("groupingID", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Guid GroupingID { get; set; } + + /// + /// Gets or sets the Date/Time of the marked for deletion time. + /// + [Newtonsoft.Json.JsonProperty("markedForDeletion", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.DateTimeOffset? MarkedForDeletion { get; set; } + + /// + /// Gets or sets the message. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } + + /// + /// Gets or sets the recipients. + /// + [Newtonsoft.Json.JsonProperty("recipients", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Recipients { get; set; } + + /// + /// Gets or sets the sender. + /// + [Newtonsoft.Json.JsonProperty("sender", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Sender { get; set; } + + [Newtonsoft.Json.JsonProperty("style", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationStyle Style { get; set; } + + [Newtonsoft.Json.JsonProperty("target", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public NotificationTarget Target { get; set; } + + } + + /// + /// API standard response model. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class GroupedNotificationIEnumerableApiResponse + { + /// + /// Gets or sets the embedded data of type T. + /// + [Newtonsoft.Json.JsonProperty("data", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public System.Collections.Generic.ICollection Data { get; set; } + + /// + /// Gets or sets the error details (NULL if no error). + /// + [Newtonsoft.Json.JsonProperty("errorDetails", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string ErrorDetails { get; set; } + + /// + /// Gets or sets a value indicating whether this response is reporting an error. + /// + [Newtonsoft.Json.JsonProperty("isError", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool IsError { get; set; } + + /// + /// Gets or sets the message. + /// + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Message { get; set; } + + /// + /// Gets or sets the status. + /// + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Status { get; set; } + + } + + /// + /// Grouped notification recipient. + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public partial class GroupedNotificationRecipient + { + /// + /// Gets or sets a value indicating whether the agent has picked up the notification. + /// + [Newtonsoft.Json.JsonProperty("agentPickup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool AgentPickup { get; set; } + + /// + /// Gets or sets a value indicating whether the client has picked up the notification. + /// + [Newtonsoft.Json.JsonProperty("clientPickup", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool ClientPickup { get; set; } + + /// + /// Gets or sets a value indicating whether the email was sent. + /// + [Newtonsoft.Json.JsonProperty("emailSent", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public bool EmailSent { get; set; } + + /// + /// Gets or sets the identifier. + /// + [Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Id { get; set; } + + /// + /// Gets or sets the name. + /// + [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Name { get; set; } + + } + /// /// API standard response model. /// @@ -12709,6 +13622,63 @@ public enum NewAircraftDeliveryOption } + /// + /// Notification recipients. 0 = User, 1 = Mods, 2 = Admins, 3 = Everyone + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public enum NotificationRecipient + { + + User = 0, + + Mods = 1, + + Admins = 2, + + Everyone = 3, + + } + + /// + /// Notification styles. 0 = ToastInfo, 1 = MessageBoxInfo, 2 = ToastWarning, 3 = MessageBoxWarning, 4 = ToastError, 5 = MessageBoxError + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public enum NotificationStyle + { + + ToastInfo = 0, + + MessageBoxInfo = 1, + + ToastWarning = 2, + + MessageBoxWarning = 3, + + ToastError = 4, + + MessageBoxError = 5, + + } + + /// + /// Notification targets. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All + /// + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.18.2.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v11.0.0.0))")] + public enum NotificationTarget + { + + Client = 0, + + Agent = 1, + + ClientAndAgent = 2, + + Email = 3, + + All = 4, + + } + /// /// Online aviation networks. 0 = Offline, 1 = Vatsim /// diff --git a/OpenSky.Agent.Simulator/OpenAPIs/swagger.json b/OpenSky.Agent.Simulator/OpenAPIs/swagger.json index 235b6c9..5a0a624 100644 --- a/OpenSky.Agent.Simulator/OpenAPIs/swagger.json +++ b/OpenSky.Agent.Simulator/OpenAPIs/swagger.json @@ -163,6 +163,38 @@ } } }, + "/Account/usernames": { + "get": { + "tags": [ + "Account" + ], + "summary": "Gets the username list of all OpenSky users.", + "description": "sushi.at, 18/12/2023.", + "operationId": "GetUserNames", + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StringIEnumerableApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringIEnumerableApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StringIEnumerableApiResponse" + } + } + } + } + } + } + }, "/Account/users": { "get": { "tags": [ @@ -4015,6 +4047,271 @@ } } }, + "/Notification": { + "post": { + "tags": [ + "Notification" + ], + "summary": "Add a new notification.", + "description": "sushi.at, 15/12/2023.", + "operationId": "AddNotification", + "requestBody": { + "description": "The add notification model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddNotification" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/AddNotification" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/AddNotification" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + } + } + } + } + }, + "get": { + "tags": [ + "Notification" + ], + "summary": "Get notifications for specified target.", + "description": "sushi.at, 18/12/2023.", + "operationId": "GetNotifications", + "parameters": [ + { + "name": "target", + "in": "query", + "description": "The target for the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All", + "schema": { + "$ref": "#/components/schemas/NotificationTarget" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ClientNotificationIEnumerableApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientNotificationIEnumerableApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ClientNotificationIEnumerableApiResponse" + } + } + } + } + } + } + }, + "/Notification/{notificationID}/{target}": { + "put": { + "tags": [ + "Notification" + ], + "summary": "Confirm successful pickup of a notification for the specified target.", + "description": "sushi.at, 18/12/2023.", + "operationId": "ConfirmNotificationPickup", + "parameters": [ + { + "name": "notificationID", + "in": "path", + "description": "Identifier for the notification.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "target", + "in": "path", + "description": "The target of the notification. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All", + "required": true, + "schema": { + "$ref": "#/components/schemas/NotificationTarget" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + } + } + } + } + } + }, + "/Notification/{groupingID}": { + "delete": { + "tags": [ + "Notification" + ], + "summary": "Delete specified notification group.", + "description": "sushi.at, 19/12/2023.", + "operationId": "DeleteNotification", + "parameters": [ + { + "name": "groupingID", + "in": "path", + "description": "Identifier for the grouping.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + } + } + } + } + } + }, + "/Notification/fallbackEmailNow/{groupingID}": { + "put": { + "tags": [ + "Notification" + ], + "summary": "Active fallback to email NOW for specified notification.", + "description": "sushi.at, 19/12/2023.", + "operationId": "FallbackNotificationToEmailNow", + "parameters": [ + { + "name": "groupingID", + "in": "path", + "description": "Identifier for the grouping.", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/StringApiResponse" + } + } + } + } + } + } + }, + "/Notification/all": { + "get": { + "tags": [ + "Notification" + ], + "summary": "Get all currently active notifications.", + "description": "sushi.at, 19/12/2023.", + "operationId": "GetAllNotifications", + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/GroupedNotificationIEnumerableApiResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/GroupedNotificationIEnumerableApiResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/GroupedNotificationIEnumerableApiResponse" + } + } + } + } + } + } + }, "/WorldStatistics": { "get": { "tags": [ @@ -4201,6 +4498,60 @@ "additionalProperties": false, "description": "API standard response model." }, + "AddNotification": { + "required": [ + "message" + ], + "type": "object", + "properties": { + "displayTimeout": { + "type": "integer", + "description": "Optional: Gets or sets the number of seconds after which to auto-dismiss the notification (or NULL for no\r\ntimeout)", + "format": "int32", + "nullable": true + }, + "emailFallbackHours": { + "type": "integer", + "description": "Optional: Gets or sets the number of hours after which the message gets sent via email if no client picked it up.", + "format": "int32", + "nullable": true + }, + "expiresInMinutes": { + "type": "integer", + "description": "Optional: Gets or sets the expiration in minutes.", + "format": "int32", + "nullable": true + }, + "message": { + "maxLength": 500, + "minLength": 0, + "type": "string", + "description": "Gets or sets the message." + }, + "recipientType": { + "$ref": "#/components/schemas/NotificationRecipient" + }, + "recipientUserName": { + "maxLength": 256, + "minLength": 0, + "type": "string", + "description": "Gets or sets the recipient username (only if recipient type is user).", + "nullable": true + }, + "sendAsSystem": { + "type": "boolean", + "description": "Gets or sets a value indicating whether to send the notification as \"OpenSky System\"" + }, + "style": { + "$ref": "#/components/schemas/NotificationStyle" + }, + "target": { + "$ref": "#/components/schemas/NotificationTarget" + } + }, + "additionalProperties": false, + "description": "Add notification model." + }, "Aircraft": { "required": [ "airportICAO", @@ -5568,6 +5919,77 @@ "additionalProperties": false, "description": "Change password model." }, + "ClientNotification": { + "required": [ + "message" + ], + "type": "object", + "properties": { + "displayTimeout": { + "type": "integer", + "description": "Optional: The number of seconds after which to auto-dismiss the notification (or NULL for no\r\ntimeout)", + "format": "int32", + "nullable": true + }, + "id": { + "type": "string", + "description": "Gets or sets the identifier of the notification.", + "format": "uuid" + }, + "message": { + "maxLength": 500, + "minLength": 0, + "type": "string", + "description": "Gets or sets the message." + }, + "sender": { + "maxLength": 256, + "minLength": 0, + "type": "string", + "description": "Gets or sets the sender (or NULL for OpenSky System).", + "nullable": true + }, + "style": { + "$ref": "#/components/schemas/NotificationStyle" + } + }, + "additionalProperties": false, + "description": "Client/Agent notification model." + }, + "ClientNotificationIEnumerableApiResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ClientNotification" + }, + "description": "Gets or sets the embedded data of type T.", + "nullable": true + }, + "errorDetails": { + "type": "string", + "description": "Gets or sets the error details (NULL if no error).", + "nullable": true + }, + "isError": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this response is reporting an error." + }, + "message": { + "type": "string", + "description": "Gets or sets the message.", + "nullable": true + }, + "status": { + "type": "string", + "description": "Gets or sets the status.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "API standard response model." + }, "Country": { "enum": [ 1, @@ -7755,6 +8177,129 @@ "additionalProperties": false, "description": "Ground operations model." }, + "GroupedNotification": { + "type": "object", + "properties": { + "displayTimeout": { + "type": "integer", + "description": "Gets or sets the display timeout.", + "format": "int32", + "nullable": true + }, + "emailFallback": { + "type": "string", + "description": "Gets or sets the Date/Time of the email fallback.", + "format": "date-time", + "nullable": true + }, + "expires": { + "type": "string", + "description": "Gets or sets the Date/Time of the expiration.", + "format": "date-time", + "nullable": true + }, + "groupingID": { + "type": "string", + "description": "Gets or sets the identifier of the grouping.", + "format": "uuid" + }, + "markedForDeletion": { + "type": "string", + "description": "Gets or sets the Date/Time of the marked for deletion time.", + "format": "date-time", + "nullable": true + }, + "message": { + "type": "string", + "description": "Gets or sets the message.", + "nullable": true + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupedNotificationRecipient" + }, + "description": "Gets or sets the recipients.", + "nullable": true + }, + "sender": { + "type": "string", + "description": "Gets or sets the sender.", + "nullable": true + }, + "style": { + "$ref": "#/components/schemas/NotificationStyle" + }, + "target": { + "$ref": "#/components/schemas/NotificationTarget" + } + }, + "additionalProperties": false, + "description": "Grouped notification model." + }, + "GroupedNotificationIEnumerableApiResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GroupedNotification" + }, + "description": "Gets or sets the embedded data of type T.", + "nullable": true + }, + "errorDetails": { + "type": "string", + "description": "Gets or sets the error details (NULL if no error).", + "nullable": true + }, + "isError": { + "type": "boolean", + "description": "Gets or sets a value indicating whether this response is reporting an error." + }, + "message": { + "type": "string", + "description": "Gets or sets the message.", + "nullable": true + }, + "status": { + "type": "string", + "description": "Gets or sets the status.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "API standard response model." + }, + "GroupedNotificationRecipient": { + "type": "object", + "properties": { + "agentPickup": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the agent has picked up the notification." + }, + "clientPickup": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the client has picked up the notification." + }, + "emailSent": { + "type": "boolean", + "description": "Gets or sets a value indicating whether the email was sent." + }, + "id": { + "type": "string", + "description": "Gets or sets the identifier.", + "nullable": true + }, + "name": { + "type": "string", + "description": "Gets or sets the name.", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Grouped notification recipient." + }, "GuidApiResponse": { "type": "object", "properties": { @@ -8150,6 +8695,84 @@ "OutsourceFerry" ] }, + "NotificationRecipient": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer", + "description": "Notification recipients. 0 = User, 1 = Mods, 2 = Admins, 3 = Everyone", + "format": "int32", + "x-enumNames": [ + "User", + "Mods", + "Admins", + "Everyone" + ], + "x-enum-varnames": [ + "User", + "Mods", + "Admins", + "Everyone" + ] + }, + "NotificationStyle": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "type": "integer", + "description": "Notification styles. 0 = ToastInfo, 1 = MessageBoxInfo, 2 = ToastWarning, 3 = MessageBoxWarning, 4 = ToastError, 5 = MessageBoxError", + "format": "int32", + "x-enumNames": [ + "ToastInfo", + "MessageBoxInfo", + "ToastWarning", + "MessageBoxWarning", + "ToastError", + "MessageBoxError" + ], + "x-enum-varnames": [ + "ToastInfo", + "MessageBoxInfo", + "ToastWarning", + "MessageBoxWarning", + "ToastError", + "MessageBoxError" + ] + }, + "NotificationTarget": { + "enum": [ + 0, + 1, + 2, + 3, + 4 + ], + "type": "integer", + "description": "Notification targets. 0 = Client, 1 = Agent, 2 = ClientAndAgent, 3 = Email, 4 = All", + "format": "int32", + "x-enumNames": [ + "Client", + "Agent", + "ClientAndAgent", + "Email", + "All" + ], + "x-enum-varnames": [ + "Client", + "Agent", + "ClientAndAgent", + "Email", + "All" + ] + }, "OnlineNetwork": { "enum": [ 0, diff --git a/OpenSky.Agent/Views/Models/StartupViewModel.cs b/OpenSky.Agent/Views/Models/StartupViewModel.cs index 87ed595..8ace3df 100644 --- a/OpenSky.Agent/Views/Models/StartupViewModel.cs +++ b/OpenSky.Agent/Views/Models/StartupViewModel.cs @@ -216,123 +216,232 @@ public StartupViewModel() } }); - // Check for new flight from API - new Thread( - () => - { - if (UserSessionService.Instance.IsUserLoggedIn) - { - _ = UserSessionService.Instance.UpdateUserRoles().Result; - _ = UserSessionService.Instance.RefreshLinkedAccounts().Result; - _ = UserSessionService.Instance.RefreshUserAccountOverview().Result; - Simulator.Instance.OpenSkyUserName = UserSessionService.Instance.Username; - UpdateGUIDelegate updateMenu = this.UpdateMainMenu; - Application.Current.Dispatcher.BeginInvoke(updateMenu); - } - else - { - Simulator.Instance.OpenSkyUserName = null; - } + // Start background worker threads + new Thread(this.CheckForNewFlights) { Name = "OpenSky.StartupViewModel.CheckForNewFlights" }.Start(); + new Thread(this.CheckNotifications) { Name = "OpenSky.StartupViewModel.CheckNotifications" }.Start(); + } - UserSessionService.Instance.PropertyChanged += (sender, e) => - { - if (e.PropertyName == nameof(UserSessionService.Instance.IsUserLoggedIn)) - { - if (UserSessionService.Instance.IsUserLoggedIn) - { - _ = UserSessionService.Instance.UpdateUserRoles().Result; - _ = UserSessionService.Instance.RefreshLinkedAccounts().Result; - _ = UserSessionService.Instance.RefreshUserAccountOverview().Result; - Simulator.Instance.OpenSkyUserName = UserSessionService.Instance.Username; - UpdateGUIDelegate updateMenu = this.UpdateMainMenu; - Application.Current.Dispatcher.BeginInvoke(updateMenu); - } - else - { - Simulator.Instance.OpenSkyUserName = null; - } - } - }; + /// ------------------------------------------------------------------------------------------------- + /// + /// Check for notifications. + /// + /// + /// sushi.at, 19/12/2023. + /// + /// ------------------------------------------------------------------------------------------------- + private void CheckNotifications() + { + // Wait for window to load up properly + Thread.Sleep(5000); - while (!SleepScheduler.IsShutdownInProgress) + while (!SleepScheduler.IsShutdownInProgress) + { + if (UserSessionService.Instance.IsUserLoggedIn) + { + try + { + var result = AgentOpenSkyService.Instance.GetNotificationsAsync(NotificationTarget.Agent).Result; + if (!result.IsError) { - if (UserSessionService.Instance.IsUserLoggedIn) + if (result.Data.Count > 0) { - try + UpdateGUIDelegate showNotifications = () => { - // Check for active flight - var result = AgentOpenSkyService.Instance.GetFlightAsync().Result; - if (!result.IsError) + foreach (var notificationData in result.Data) { - if (result.Data.Id != Guid.Empty) + if (notificationData.Style is NotificationStyle.ToastInfo or NotificationStyle.ToastWarning or NotificationStyle.ToastError) { - UpdateGUIDelegate resetPausedFlights = () => this.PausedFlights.Clear(); - Application.Current.Dispatcher.BeginInvoke(resetPausedFlights); + var icon = notificationData.Style switch + { + NotificationStyle.ToastWarning => ExtendedMessageBoxImage.Warning, + NotificationStyle.ToastError => ExtendedMessageBoxImage.Error, + _ => ExtendedMessageBoxImage.Information + }; - if (Simulator.Instance.Flight == null) + var notification = new OpenSkyNotification($"Notification from \"{notificationData.Sender}\"", notificationData.Message, MessageBoxButton.OK, icon, notificationData.DisplayTimeout ?? 0); + if (notificationData.Style == NotificationStyle.ToastWarning) { - Simulator.Instance.Flight = result.Data; - Simulator.Instance.VatsimUserID = UserSessionService.Instance.LinkedAccounts?.VatsimID; + notification.SetWarningColorStyle(); } - else + + if (notificationData.Style == NotificationStyle.ToastError) { - if (Simulator.Instance.Flight.Id != result.Data.Id) - { - // Different flight from current one? - Simulator.Instance.StopTracking(true); - } + notification.SetErrorColorStyle(); } + + FlightTracking.Open(); + FlightTracking.Instance.ShowNotification(notification); } - else + + if (notificationData.Style is NotificationStyle.MessageBoxInfo or NotificationStyle.MessageBoxWarning or NotificationStyle.MessageBoxError) { - if (Simulator.Instance.Flight != null) + var icon = notificationData.Style switch { - Simulator.Instance.Flight = null; - } + NotificationStyle.MessageBoxWarning => ExtendedMessageBoxImage.Warning, + NotificationStyle.MessageBoxError => ExtendedMessageBoxImage.Error, + _ => ExtendedMessageBoxImage.Information + }; - // Check for paused flights - var pausedResult = AgentOpenSkyService.Instance.GetMyFlightsAsync().Result; - if (!result.IsError) + var messageBox = new OpenSkyMessageBox($"Notification from \"{notificationData.Sender}\"", notificationData.Message, MessageBoxButton.OK, icon, notificationData.DisplayTimeout ?? 0); + if (notificationData.Style == NotificationStyle.MessageBoxWarning) { - UpdateGUIDelegate addPausedFlights = () => - { - this.PausedFlights.Clear(); - foreach (var flight in pausedResult.Data.Where(f => f.Paused.HasValue)) - { - this.PausedFlights.Add(flight); - } - }; - Application.Current.Dispatcher.BeginInvoke(addPausedFlights); + messageBox.SetWarningColorStyle(); } - else + + if (notificationData.Style == NotificationStyle.MessageBoxError) { - Debug.WriteLine("Error checking for paused flights: " + result.Message + "\r\n" + result.ErrorDetails); + messageBox.SetErrorColorStyle(); } + + FlightTracking.Open(); + FlightTracking.Instance.ShowMessageBox(messageBox); } } - else + }; + Application.Current.Dispatcher.BeginInvoke(showNotifications); + + foreach (var notification in result.Data) + { + _ = AgentOpenSkyService.Instance.ConfirmNotificationPickupAsync(notification.Id, NotificationTarget.Agent).Result; + } + } + } + else + { + Debug.WriteLine($"Error checking for notifications: {result.Message}\r\n{result.ErrorDetails}"); + } + } + catch (Exception ex) + { + Debug.WriteLine("Error checking for notifications: " + ex); + } + + SleepScheduler.SleepFor(TimeSpan.FromMinutes(1)); + } + } + } + + /// ------------------------------------------------------------------------------------------------- + /// + /// Check for new flight from API. + /// + /// + /// sushi.at, 18/12/2023. + /// + /// ------------------------------------------------------------------------------------------------- + private void CheckForNewFlights() + { + if (UserSessionService.Instance.IsUserLoggedIn) + { + _ = UserSessionService.Instance.UpdateUserRoles().Result; + _ = UserSessionService.Instance.RefreshLinkedAccounts().Result; + _ = UserSessionService.Instance.RefreshUserAccountOverview().Result; + Simulator.Instance.OpenSkyUserName = UserSessionService.Instance.Username; + UpdateGUIDelegate updateMenu = this.UpdateMainMenu; + Application.Current.Dispatcher.BeginInvoke(updateMenu); + } + else + { + Simulator.Instance.OpenSkyUserName = null; + } + + UserSessionService.Instance.PropertyChanged += (sender, e) => + { + if (e.PropertyName == nameof(UserSessionService.Instance.IsUserLoggedIn)) + { + if (UserSessionService.Instance.IsUserLoggedIn) + { + _ = UserSessionService.Instance.UpdateUserRoles().Result; + _ = UserSessionService.Instance.RefreshLinkedAccounts().Result; + _ = UserSessionService.Instance.RefreshUserAccountOverview().Result; + Simulator.Instance.OpenSkyUserName = UserSessionService.Instance.Username; + UpdateGUIDelegate updateMenu = this.UpdateMainMenu; + Application.Current.Dispatcher.BeginInvoke(updateMenu); + } + else + { + Simulator.Instance.OpenSkyUserName = null; + } + } + }; + + while (!SleepScheduler.IsShutdownInProgress) + { + if (UserSessionService.Instance.IsUserLoggedIn) + { + try + { + // Check for active flight + var result = AgentOpenSkyService.Instance.GetFlightAsync().Result; + if (!result.IsError) + { + if (result.Data.Id != Guid.Empty) + { + UpdateGUIDelegate resetPausedFlights = () => this.PausedFlights.Clear(); + Application.Current.Dispatcher.BeginInvoke(resetPausedFlights); + + if (Simulator.Instance.Flight == null) + { + Simulator.Instance.Flight = result.Data; + Simulator.Instance.VatsimUserID = UserSessionService.Instance.LinkedAccounts?.VatsimID; + } + else + { + if (Simulator.Instance.Flight.Id != result.Data.Id) { - Debug.WriteLine("Error checking for new flight: " + result.Message + "\r\n" + result.ErrorDetails); + // Different flight from current one? + Simulator.Instance.StopTracking(true); } } - catch (Exception ex) + } + else + { + if (Simulator.Instance.Flight != null) { - Debug.WriteLine("Error checking for new flight: " + ex); + Simulator.Instance.Flight = null; } - } - this.NextFlightUpdateCheckSeconds = Simulator.Instance.Flight == null ? 30 : 120; - while (this.NextFlightUpdateCheckSeconds > 0 && !SleepScheduler.IsShutdownInProgress) - { - Thread.Sleep(1000); - if (this.NextFlightUpdateCheckSeconds > 0) + // Check for paused flights + var pausedResult = AgentOpenSkyService.Instance.GetMyFlightsAsync().Result; + if (!result.IsError) + { + UpdateGUIDelegate addPausedFlights = () => + { + this.PausedFlights.Clear(); + foreach (var flight in pausedResult.Data.Where(f => f.Paused.HasValue)) + { + this.PausedFlights.Add(flight); + } + }; + Application.Current.Dispatcher.BeginInvoke(addPausedFlights); + } + else { - this.NextFlightUpdateCheckSeconds--; + Debug.WriteLine("Error checking for paused flights: " + result.Message + "\r\n" + result.ErrorDetails); } } } - }) - { Name = "OpenSky.StartupViewModel.CheckForFlights" }.Start(); + else + { + Debug.WriteLine($"Error checking for new flight: {result.Message}\r\n{result.ErrorDetails}"); + } + } + catch (Exception ex) + { + Debug.WriteLine("Error checking for new flight: " + ex); + } + } + + this.NextFlightUpdateCheckSeconds = Simulator.Instance.Flight == null ? 30 : 120; + while (this.NextFlightUpdateCheckSeconds > 0 && !SleepScheduler.IsShutdownInProgress) + { + Thread.Sleep(1000); + if (this.NextFlightUpdateCheckSeconds > 0) + { + this.NextFlightUpdateCheckSeconds--; + } + } + } } /// ------------------------------------------------------------------------------------------------- From 6c298019570084187be91735e16d38d4aadfc471 Mon Sep 17 00:00:00 2001 From: "sushi.at" Date: Tue, 19 Dec 2023 19:28:13 +0000 Subject: [PATCH 2/2] Added changelog and bumped version --- .../Properties/AssemblyInfo.cs | 4 ++-- OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj | 10 ++++++++-- OpenSky.Agent.Simulator/Properties/AssemblyInfo.cs | 4 ++-- OpenSky.Agent.Simulator/packages.config | 6 +++--- OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs | 4 ++-- OpenSky.Agent/OpenSky.Agent.csproj | 6 +++--- OpenSky.Agent/Properties/AssemblyInfo.cs | 4 ++-- changelog.txt | 5 +++++ 8 files changed, 27 insertions(+), 16 deletions(-) diff --git a/OpenSky.Agent.SimConnectMSFS/Properties/AssemblyInfo.cs b/OpenSky.Agent.SimConnectMSFS/Properties/AssemblyInfo.cs index 77e9a3c..ef8bbc7 100644 --- a/OpenSky.Agent.SimConnectMSFS/Properties/AssemblyInfo.cs +++ b/OpenSky.Agent.SimConnectMSFS/Properties/AssemblyInfo.cs @@ -17,5 +17,5 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("1f9cbede-669d-4510-bca2-e6ad29d6a498")] -[assembly: AssemblyVersion("0.5.10")] -[assembly: AssemblyFileVersion("0.5.10")] +[assembly: AssemblyVersion("0.5.11")] +[assembly: AssemblyFileVersion("0.5.11")] diff --git a/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj b/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj index 0762a6b..ddc93e4 100644 --- a/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj +++ b/OpenSky.Agent.Simulator/OpenSky.Agent.Simulator.csproj @@ -56,8 +56,14 @@ - - ..\packages\Syncfusion.SfProgressBar.WPF.23.2.7\lib\net46\Syncfusion.SfProgressBar.WPF.dll + + ..\packages\Syncfusion.Licensing.24.1.41\lib\net46\Syncfusion.Licensing.dll + + + ..\packages\Syncfusion.SfProgressBar.WPF.24.1.41\lib\net46\Syncfusion.SfProgressBar.WPF.dll + + + ..\packages\Syncfusion.Shared.WPF.24.1.41\lib\net46\Syncfusion.Shared.WPF.dll diff --git a/OpenSky.Agent.Simulator/Properties/AssemblyInfo.cs b/OpenSky.Agent.Simulator/Properties/AssemblyInfo.cs index da1b1cd..c2a0b1c 100644 --- a/OpenSky.Agent.Simulator/Properties/AssemblyInfo.cs +++ b/OpenSky.Agent.Simulator/Properties/AssemblyInfo.cs @@ -18,6 +18,6 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("30c467e8-2eee-41e5-be01-0142a61ba171")] -[assembly: AssemblyVersion("0.5.10")] -[assembly: AssemblyFileVersion("0.5.10")] +[assembly: AssemblyVersion("0.5.11")] +[assembly: AssemblyFileVersion("0.5.11")] [assembly: InternalsVisibleTo("OpenSky.Agent")] diff --git a/OpenSky.Agent.Simulator/packages.config b/OpenSky.Agent.Simulator/packages.config index 7376c9b..552a7c3 100644 --- a/OpenSky.Agent.Simulator/packages.config +++ b/OpenSky.Agent.Simulator/packages.config @@ -6,9 +6,9 @@ - - - + + + \ No newline at end of file diff --git a/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs b/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs index 5b54ffe..d0c3093 100644 --- a/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs +++ b/OpenSky.Agent.UdpXPlane11/Properties/AssemblyInfo.cs @@ -17,5 +17,5 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("dfbda2b8-5775-4766-be86-d729fcf20de1")] -[assembly: AssemblyVersion("0.5.10")] -[assembly: AssemblyFileVersion("0.5.10")] +[assembly: AssemblyVersion("0.5.11")] +[assembly: AssemblyFileVersion("0.5.11")] diff --git a/OpenSky.Agent/OpenSky.Agent.csproj b/OpenSky.Agent/OpenSky.Agent.csproj index 8e0bc11..7ce8f62 100644 --- a/OpenSky.Agent/OpenSky.Agent.csproj +++ b/OpenSky.Agent/OpenSky.Agent.csproj @@ -392,13 +392,13 @@ 0.1.8 - 23.2.7 + 24.1.41 - 23.2.7 + 24.1.41 - 23.2.7 + 24.1.41 2.10.0 diff --git a/OpenSky.Agent/Properties/AssemblyInfo.cs b/OpenSky.Agent/Properties/AssemblyInfo.cs index 2e37f1b..0dcbb01 100644 --- a/OpenSky.Agent/Properties/AssemblyInfo.cs +++ b/OpenSky.Agent/Properties/AssemblyInfo.cs @@ -21,8 +21,8 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("0.5.10")] -[assembly: AssemblyFileVersion("0.5.10")] +[assembly: AssemblyVersion("0.5.11")] +[assembly: AssemblyFileVersion("0.5.11")] // This allows us to detect debug mode in XAML #if DEBUG diff --git a/changelog.txt b/changelog.txt index a72218c..f1dd190 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,11 @@ OpenSky Flight Tracking Agent Changelog ====================================================================================== +-------------------------------------------------------------------------------------- +Version 0.5.11 (ALPHA5) +-------------------------------------------------------------------------------------- +- Added notifications + -------------------------------------------------------------------------------------- Version 0.5.10 (ALPHA5) --------------------------------------------------------------------------------------