Reduce steps to 1 when integrating Shopify and start adding more API calls for Shopify to reduce JS logic

This commit is contained in:
Kukks
2020-09-19 16:53:45 +02:00
parent 4516bbdadd
commit 19cc93daae
5 changed files with 73 additions and 63 deletions

View File

@@ -1,28 +1,32 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Shopify;
using BTCPayServer.Services.Shopify.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Nethereum.Util;
namespace BTCPayServer.Controllers
{
public partial class StoresController
{
private static string _cachedBasejavascript;
private static string _cachedShopifyJavascript;
private async Task<string> GetJavascript()
{
if (!string.IsNullOrEmpty(_cachedBasejavascript))
if (!string.IsNullOrEmpty(_cachedShopifyJavascript))
{
return _cachedBasejavascript;
return _cachedShopifyJavascript;
}
string[] fileList = _BtcpayServerOptions.BundleJsCss
@@ -35,10 +39,10 @@ namespace BTCPayServer.Controllers
await using var stream = _webHostEnvironment.WebRootFileProvider
.GetFileInfo(file).CreateReadStream();
using var reader = new StreamReader(stream);
_cachedBasejavascript += Environment.NewLine + await reader.ReadToEndAsync();
_cachedShopifyJavascript += Environment.NewLine + await reader.ReadToEndAsync();
}
return _cachedBasejavascript;
return _cachedShopifyJavascript;
}
[AllowAnonymous]
@@ -70,7 +74,7 @@ namespace BTCPayServer.Controllers
{
try
{
//https://{apikey}:{password}@{hostname}/admin/api/{version}/{resource}.json
//https://{apikey}:{password}@{hostname}/admin/api/{version}/{resource}.json
var parsedUrl = new Uri(exampleUrl);
var userInfo = parsedUrl.UserInfo.Split(":");
vm.Shopify = new ShopifySettings()
@@ -108,12 +112,20 @@ namespace BTCPayServer.Controllers
catch
{
TempData[WellKnownTempData.ErrorMessage] =
"Shopify rejected provided credentials, please correct values and again";
"Shopify rejected provided credentials, please correct values and try again";
return View("Integrations", vm);
}
shopify.CredentialsValid = true;
var scopesGranted = await apiClient.CheckScopes();
if (!scopesGranted.Contains("read_orders") || !scopesGranted.Contains("write_script_tags"))
{
TempData[WellKnownTempData.ErrorMessage] =
"Please grant the private app permissions for read_orders, write_script_tags";
return View("Integrations", vm);
}
var blob = CurrentStore.GetStoreBlob();
blob.Shopify = shopify;
if (CurrentStore.SetStoreBlob(blob))
@@ -121,26 +133,7 @@ namespace BTCPayServer.Controllers
await _Repo.UpdateStore(CurrentStore);
}
TempData[WellKnownTempData.SuccessMessage] = "Shopify credentials successfully updated";
break;
}
case "ShopifyIntegrate":
{
var blob = CurrentStore.GetStoreBlob();
var apiClient = new ShopifyApiClient(clientFactory, blob.Shopify.CreateShopifyApiCredentials());
var result = await apiClient.CreateScript(Url.Action("ShopifyJavascript", "Stores",
new {storeId = CurrentStore.Id}, Request.Scheme));
blob.Shopify.ScriptId = result.ScriptTag?.Id.ToString(CultureInfo.InvariantCulture);
blob.Shopify.IntegratedAt = DateTimeOffset.UtcNow;
if (CurrentStore.SetStoreBlob(blob))
{
await _Repo.UpdateStore(CurrentStore);
}
TempData[WellKnownTempData.SuccessMessage] = "Shopify integration successfully turned on";
TempData[WellKnownTempData.SuccessMessage] = "Shopify integration successfully updated";
break;
}
case "ShopifyClearCredentials":

View File

@@ -56,7 +56,6 @@ namespace BTCPayServer.Controllers
BTCPayNetworkProvider networkProvider,
RateFetcher rateFactory,
ExplorerClientProvider explorerProvider,
IFeeProviderFactory feeRateProvider,
LanguageService langService,
PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
SettingsRepository settingsRepository,
@@ -82,7 +81,6 @@ namespace BTCPayServer.Controllers
_EventAggregator = eventAggregator;
_NetworkProvider = networkProvider;
_ExplorerProvider = explorerProvider;
_FeeRateProvider = feeRateProvider;
_ServiceProvider = serviceProvider;
_BtcpayServerOptions = btcpayServerOptions;
_BTCPayEnv = btcpayEnv;
@@ -93,7 +91,6 @@ namespace BTCPayServer.Controllers
readonly IServiceProvider _ServiceProvider;
readonly BTCPayNetworkProvider _NetworkProvider;
private readonly ExplorerClientProvider _ExplorerProvider;
private readonly IFeeProviderFactory _FeeRateProvider;
readonly BTCPayWalletProvider _WalletProvider;
readonly AccessTokenController _TokenController;
readonly StoreRepository _Repo;

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Services.Shopify.ApiModels.DataHolders;
namespace BTCPayServer.Services.Shopify.ApiModels

View File

@@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Services.Shopify.ApiModels;
using DBriize.Utils;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Services.Shopify
{
@@ -23,6 +26,7 @@ namespace BTCPayServer.Services.Shopify
{
_httpClient = new HttpClient();
}
_credentials = credentials;
var bearer = $"{credentials.ApiKey}:{credentials.ApiPassword}";
@@ -31,9 +35,11 @@ namespace BTCPayServer.Services.Shopify
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + bearer);
}
private HttpRequestMessage CreateRequest(string shopName, HttpMethod method, string action)
private HttpRequestMessage CreateRequest(string shopName, HttpMethod method, string action,
string relativeUrl = null)
{
var url = $"https://{(shopName.Contains(".", StringComparison.InvariantCulture)? shopName: $"{shopName}.myshopify.com")}/admin/api/2020-07/" + action;
var url =
$"https://{(shopName.Contains(".", StringComparison.InvariantCulture) ? shopName : $"{shopName}.myshopify.com")}/{relativeUrl ?? ("admin/api/2020-07/" + action)}";
var req = new HttpRequestMessage(method, url);
return req;
}
@@ -49,12 +55,8 @@ namespace BTCPayServer.Services.Shopify
public async Task<CreateWebhookResponse> CreateWebhook(string topic, string address, string format = "json")
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Post, $"webhooks.json");
req.Content = new StringContent(JsonConvert.SerializeObject(new
{
topic,
address,
format
}), Encoding.UTF8, "application/json");
req.Content = new StringContent(JsonConvert.SerializeObject(new {topic, address, format}), Encoding.UTF8,
"application/json");
var strResp = await SendRequest(req);
return JsonConvert.DeserializeObject<CreateWebhookResponse>(strResp);
@@ -63,18 +65,24 @@ namespace BTCPayServer.Services.Shopify
public async Task RemoveWebhook(string id)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Delete, $"webhooks/{id}.json");
await SendRequest(req);
var strResp = await SendRequest(req);
}
public async Task<CreateScriptResponse> CreateScript(string scriptUrl, string evt = "onload", string scope = "order_status")
public async Task<string[]> CheckScopes()
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Delete, null, "admin/oauth/access_scopes.json");
return JObject.Parse(await SendRequest(req))["access_scopes"].Values<JToken>()
.Select(token => token["handle"].Value<string>()).ToArray();
}
public async Task<CreateScriptResponse> CreateScript(string scriptUrl, string evt = "onload",
string scope = "order_status")
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Post, $"script_tags.json");
req.Content = new StringContent(JsonConvert.SerializeObject(new
{
@event = evt,
src = scriptUrl,
display_scope = scope
}), Encoding.UTF8, "application/json");
req.Content =
new StringContent(
JsonConvert.SerializeObject(new {@event = evt, src = scriptUrl, display_scope = scope}),
Encoding.UTF8, "application/json");
var strResp = await SendRequest(req);
return JsonConvert.DeserializeObject<CreateScriptResponse>(strResp);
@@ -108,6 +116,26 @@ namespace BTCPayServer.Services.Shopify
return JsonConvert.DeserializeObject<TransactionsCreateResp>(strResp);
}
public async Task UpdateOrderNote(string orderId, string note)
{
var postJson = JsonConvert.SerializeObject(new {order = new {id = orderId, note}});
var req = CreateRequest(_credentials.ShopName, HttpMethod.Put, $"orders/{orderId}.json");
req.Content = new StringContent(postJson, Encoding.UTF8, "application/json");
await SendRequest(req);
}
public async Task<ShopifyOrder> GetOrder(string orderId)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get,
$"orders/{orderId}.json?fields=id,total_price,currency,transactions,financial_status");
var strResp = await SendRequest(req);
return JsonConvert.DeserializeObject<ShopifyOrder>(strResp);
}
public async Task<long> OrdersCount()
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, $"orders/count.json");
@@ -126,11 +154,11 @@ namespace BTCPayServer.Services.Shopify
return strResp?.Contains(orderId, StringComparison.OrdinalIgnoreCase) == true;
}
}
}
public class ShopifyApiClientCredentials
{
public class ShopifyApiClientCredentials
{
public string ShopName { get; set; }
public string ApiKey { get; set; }
public string ApiPassword { get; set; }
}
}

View File

@@ -81,7 +81,7 @@ function promptExampleUrl(){
}
else
{
<p>Checkout scripts should be automatically added to the order status page to display the BTCPay payment option.</p>
<p class="alert alert-success">Checkout scripts should be automatically added to the order status page to display the BTCPay payment option.</p>
}
<p class="alert alert-info">
Please add a payment method at <a href="https://@(shopify.ShopName).myshopify.com/admin/settings/payments" target="_blank"> Settings > Payments > Manual Payment Methods</a> with the name <kbd>Bitcoin with BTCPay Server</kbd>
@@ -90,10 +90,6 @@ function promptExampleUrl(){
@if (shopifyCredsSet)
{
if (!shopify.IntegratedAt.HasValue)
{
<button name="command" type="submit" class="btn btn-primary" value="ShopifyIntegrate">Integrate Shopify Order Paid Marking</button>
}
<button name="command" type="submit" class="btn btn-danger" value="ShopifyClearCredentials">
@(shopify.IntegratedAt.HasValue ? "Stop Shopify calls and clear credentials" : "Clear credentials")
</button>