Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for 107 - Add Categories to Product #185

Open
wants to merge 5 commits into
base: nopCommerce_4.10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Nop.Plugin.Api.Client/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1"/>
</startup>
</configuration>
217 changes: 217 additions & 0 deletions Nop.Plugin.Api.Client/Clients/BaseRestClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
using System;
using System.Globalization;
using System.Net;
using System.Text;
using Nop.Plugin.Api.Client.Exceptions;
using Nop.Plugin.Api.Client.Security;
using Nop.Plugin.Api.Client.Serialization;
using Polly;
using RestSharp;
using RestSharp.Authenticators;
using RestSharp.Deserializers;
using RestSharp.Extensions;
using RestSharp.Serializers;

namespace Nop.Plugin.Api.Client.Clients
{
public abstract class BaseRestClient
{
private readonly NopApiClient _parent;

private const int DefaultRetryAttempts = 10;

private const int DefaultDelayBetweenRetryAttemptsInMs = 250;

private Token _currentToken;

private IDeserializer _deserializer;

private ISerializer _serializer;


protected BaseRestClient(NopApiClient parent)
{
_parent = parent;
}

protected RestRequest GetRequest(string resource, Method method = Method.GET)
{
return new RestRequest(resource, method) { RequestFormat = DataFormat.Json };
}

protected IRestResponse<T> Execute<T>(
IRestRequest request,
bool throwIfError = true,
int retryAttempts = DefaultRetryAttempts,
int waitTimeBetweenAttempts = DefaultDelayBetweenRetryAttemptsInMs)
where T : new()
{
InitRequest(request);

var policy = GetPolicy<IRestResponse<T>>(retryAttempts, waitTimeBetweenAttempts);

return policy.Execute(
() =>
{
var response = GetClient().Execute<T>(request);

if (throwIfError)
{
Process(request, response);
}

return response;
});
}

protected ISerializer Serializer
{
get => _serializer ?? (_serializer = new NewtonsoftSerializer());

set => _serializer = value;
}

protected IDeserializer Deserializer
{
get => _deserializer ?? (_deserializer = new NewtonsoftSerializer());

set => _deserializer = value;
}

private void Process(IRestRequest request, IRestResponse response)
{
if (response.ResponseStatus == ResponseStatus.Error && response.ErrorException != null)
{
// This is likely a transport issue such as the underlying connection was closed
throw new NopApiClientException(
$"Request to {request.Method}:{response.ResponseUri} {response.StatusCode} failed with exception",
true);
}

if (response.ResponseStatus == ResponseStatus.Error)
{
throw new NopApiClientException(
$"Failed to connect to REST API {request.Resource}, status: {response.StatusCode}",
true);
}

ThrowErrorIfAny(response);
}

protected bool HasError(IRestResponse response)
{
if (response?.Request == null)
{
return false;
}

return response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Accepted
&& response.StatusCode != HttpStatusCode.Created
&& response.StatusCode != HttpStatusCode.Continue
&& response.StatusCode != HttpStatusCode.NoContent;
}

protected void ThrowErrorIfAny(IRestResponse response, string message = null)
{
if (response?.Request == null)
{
throw new NopApiClientException("null response");
}

if (HasError(response))
{
NopApiClientExceptionDetails exceptionDetails = null;

if (response.Request.RequestFormat == DataFormat.Json)
{
if (!JsonSerializationUtility.TryDeserialize(response.Content, out exceptionDetails))
{
if (exceptionDetails == null && response.ErrorException != null)
{
exceptionDetails = new NopApiClientExceptionDetails
{
Message = response.ErrorException.Message,
ExceptionType = response.ErrorException.GetType().Name,
//ExceptionMessage = response.ErrorException.Message,
StackTrace = response.ErrorException.StackTrace
};
}
}
}

throw new NopApiClientException(
response.StatusCode,
response.ResponseUri != null ? response.ResponseUri.ToString() : string.Empty,
response.Request.Method.ToString(),
message,
exceptionDetails);
}

if (response.ErrorException != null)
{
throw new NopApiClientException(
response.StatusCode,
response.ResponseUri != null ? response.ResponseUri.ToString() : string.Empty,
response.Request.Method.ToString(),
response.ErrorException);
}
}

private RestClient GetClient()
{
var client = new RestClient(_parent.ServerUrl);

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;

// Override with Newtonsoft JSON Handler
client.AddHandler("application/json", Deserializer);
client.AddHandler("text/json", Deserializer);
client.AddHandler("text/x-json", Deserializer);
client.AddHandler("text/javascript", Deserializer);
client.AddHandler("*+json", Deserializer);

client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(
CurrentToken.AccessToken,
CurrentToken.TokenType);

return client;
}

protected Token CurrentToken => _currentToken ?? (_currentToken = GetToken());

private Token GetToken()
{
var client = new TokenClient(new Uri(_parent.ServerUrl));

return client.GetToken(_parent.ClientId, _parent.Secret);
}

private void InitRequest(IRestRequest request)
{
request.OnBeforeDeserialization = resp =>
{
// for individual resources when there's an error to make
// sure that RestException props are populated
if ((int)resp.StatusCode >= 400)
{
// have to read the bytes so .Content doesn't get populated
const string restException = "{{ \"RestException\" : {0} }}";
var content = resp.RawBytes.AsString(); //get the response content
var newJson = string.Format(restException, content);

resp.Content = null;
resp.RawBytes = Encoding.UTF8.GetBytes(newJson.ToString(CultureInfo.InvariantCulture));
}
};
}

private static Policy<T> GetPolicy<T>(int retryAttempts, int waitTimeBetweenAttempts)
{
return Policy<T>.Handle<NopApiClientException>(ex => ex.CanRetry).WaitAndRetry(
retryAttempts,
attempt => TimeSpan.FromMilliseconds(waitTimeBetweenAttempts));
}
}
}


73 changes: 73 additions & 0 deletions Nop.Plugin.Api.Client/Clients/OrdersClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// -----------------------------------------------------------------------
// <copyright from="2018" to="2018" file="OrdersClient.cs" company="Lindell Technologies">
// Copyright (c) Lindell Technologies All Rights Reserved.
// Information Contained Herein is Proprietary and Confidential.
// </copyright>
// -----------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Nop.Plugin.Api.Client.DTOs.Orders;

namespace Nop.Plugin.Api.Client.Clients
{
public class OrdersClient : BaseRestClient
{
internal OrdersClient(NopApiClient parent) : base(parent)
{
}

public IList<OrderDto> GetOrders(int sinceId = 0, DateTime? createdAtMin = null, DateTime? createdAtMax = null, int? customerId = null, int page = 1, int limit = 50)
{
var request = GetRequest("api/orders");


if (sinceId > 0)
{
request.AddQueryParameter("sinceId", sinceId.ToString());
}

if (createdAtMin.HasValue)
{
request.AddQueryParameter("createdAtMin", createdAtMin.Value.ToString(CultureInfo.InvariantCulture));
}

if (createdAtMax.HasValue)
{
request.AddQueryParameter("createdAtMax", createdAtMax.Value.ToString(CultureInfo.InvariantCulture));
}

if (customerId.GetValueOrDefault() > 0)
{
request.AddQueryParameter("customerId", customerId.GetValueOrDefault().ToString());
}

if (page > 0)
{
request.AddQueryParameter("page", page.ToString());
}

if (limit > 0)
{
request.AddQueryParameter("limit", Math.Min(250, limit).ToString());
}


return Execute<OrdersRootObject>(request).Data.Orders;
}

public IList<OrderDto> GetOrders(IEnumerable<int> ids)
{
var request = GetRequest("api/orders");

if (ids != null)
{
request.AddQueryParameter("ids", string.Join(",", ids.Select(s => s.ToString())));
}

return Execute<OrdersRootObject>(request).Data.Orders;
}
}
}
80 changes: 80 additions & 0 deletions Nop.Plugin.Api.Client/DTOs/AddressDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Newtonsoft.Json;

namespace Nop.Plugin.Api.Client.DTOs
{
[JsonObject(Title = "address")]
public class AddressDto
{
/// <summary>
/// Gets or sets the first name
/// </summary>
[JsonProperty("first_name")]
public string FirstName { get; set; }

/// <summary>
/// Gets or sets the last name
/// </summary>
[JsonProperty("last_name")]
public string LastName { get; set; }

/// <summary>
/// Gets or sets the email
/// </summary>
[JsonProperty("email")]
public string Email { get; set; }

/// <summary>
/// Gets or sets the company
/// </summary>
[JsonProperty("company")]
public string Company { get; set; }

/// <summary>
/// Gets or sets the country name
/// </summary>
[JsonProperty("country")]
public string CountryName { get; set; }

/// <summary>
/// Gets or sets the city
/// </summary>
[JsonProperty("city")]
public string City { get; set; }

/// <summary>
/// Gets or sets the address 1
/// </summary>
[JsonProperty("address1")]
public string Address1 { get; set; }

/// <summary>
/// Gets or sets the address 2
/// </summary>
[JsonProperty("address2")]
public string Address2 { get; set; }

/// <summary>
/// Gets or sets the zip/postal code
/// </summary>
[JsonProperty("zip_postal_code")]
public string ZipPostalCode { get; set; }

/// <summary>
/// Gets or sets the phone number
/// </summary>
[JsonProperty("phone_number")]
public string PhoneNumber { get; set; }

/// <summary>
/// Gets or sets the fax number
/// </summary>
[JsonProperty("fax_number")]
public string FaxNumber { get; set; }

/// <summary>
/// Gets or sets the state/province
/// </summary>
[JsonProperty("province")]
public string StateProvinceName { get; set; }
}
}
10 changes: 10 additions & 0 deletions Nop.Plugin.Api.Client/DTOs/Categories/CategoriesCountRootObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Newtonsoft.Json;

namespace Nop.Plugin.Api.Client.DTOs.Categories
{
public class CategoriesCountRootObject
{
[JsonProperty("count")]
public int Count { get; set; }
}
}
Loading