mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
Importing UI for registering and verifying Shopify credentials
This commit is contained in:
@@ -20,6 +20,7 @@ using BTCPayServer.Services;
|
|||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
|
using BTCPayServer.Services.Shopify;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
using BTCPayServer.Services.Wallets;
|
using BTCPayServer.Services.Wallets;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
@@ -964,5 +965,89 @@ namespace BTCPayServer.Controllers
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
[HttpGet]
|
||||||
|
[Route("{storeId}/integrations")]
|
||||||
|
public async Task<IActionResult> Integrations()
|
||||||
|
{
|
||||||
|
var blob = CurrentStore.GetStoreBlob();
|
||||||
|
|
||||||
|
var vm = new IntegrationsViewModel
|
||||||
|
{
|
||||||
|
Shopify = blob.Shopify
|
||||||
|
};
|
||||||
|
|
||||||
|
return View("Integrations", vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("{storeId}/integrations")]
|
||||||
|
public async Task<IActionResult> Integrations([FromServices] IHttpClientFactory clientFactory,
|
||||||
|
IntegrationsViewModel vm, string command = "")
|
||||||
|
{
|
||||||
|
if (command == "ShopifySaveCredentials")
|
||||||
|
{
|
||||||
|
var shopify = vm.Shopify;
|
||||||
|
var validCreds = shopify != null && shopify?.CredentialsPopulated() == true;
|
||||||
|
if (!validCreds)
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = "Please provide valid Shopify credentials";
|
||||||
|
//
|
||||||
|
return View("Integrations", vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiCreds = new ShopifyApiClientCredentials
|
||||||
|
{
|
||||||
|
ShopName = shopify.ShopName,
|
||||||
|
ApiKey = shopify.ApiKey,
|
||||||
|
ApiPassword = shopify.Password,
|
||||||
|
SharedSecret = shopify.SharedSecret
|
||||||
|
};
|
||||||
|
|
||||||
|
var apiClient = new ShopifyApiClient(clientFactory, null, apiCreds);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await apiClient.OrdersCount();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
TempData[WellKnownTempData.ErrorMessage] = "Shopify rejected provided credentials, please correct values and again";
|
||||||
|
//
|
||||||
|
return View("Integrations", vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shopify.CredentialsValid = true;
|
||||||
|
|
||||||
|
var blob = CurrentStore.GetStoreBlob();
|
||||||
|
blob.Shopify = shopify;
|
||||||
|
if (CurrentStore.SetStoreBlob(blob))
|
||||||
|
{
|
||||||
|
await _Repo.UpdateStore(CurrentStore);
|
||||||
|
}
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = "Shopify credentials successfully updated";
|
||||||
|
}
|
||||||
|
else if (command == "ShopifyIntegrate")
|
||||||
|
{
|
||||||
|
var shopify = vm.Shopify;
|
||||||
|
|
||||||
|
var blob = CurrentStore.GetStoreBlob();
|
||||||
|
blob.Shopify.IntegratedAt = DateTimeOffset.UtcNow;
|
||||||
|
if (CurrentStore.SetStoreBlob(blob))
|
||||||
|
{
|
||||||
|
await _Repo.UpdateStore(CurrentStore);
|
||||||
|
}
|
||||||
|
TempData[WellKnownTempData.SuccessMessage] = "Shopify integration successfully turned on";
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToAction(nameof(Integrations), new
|
||||||
|
{
|
||||||
|
storeId = CurrentStore.Id
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,28 @@ namespace BTCPayServer.Data
|
|||||||
RecommendedFeeBlockTarget = 1;
|
RecommendedFeeBlockTarget = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShopifyDataHolder Shopify { get; set; }
|
||||||
|
|
||||||
|
public class ShopifyDataHolder
|
||||||
|
{
|
||||||
|
public string ShopName { get; set; }
|
||||||
|
public string ApiKey { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string SharedSecret { get; set; }
|
||||||
|
|
||||||
|
public bool CredentialsPopulated()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
!String.IsNullOrWhiteSpace(ShopName) &&
|
||||||
|
!String.IsNullOrWhiteSpace(ApiKey) &&
|
||||||
|
!String.IsNullOrWhiteSpace(Password) &&
|
||||||
|
!String.IsNullOrWhiteSpace(SharedSecret);
|
||||||
|
}
|
||||||
|
public bool CredentialsValid { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? IntegratedAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("Use NetworkFeeMode instead")]
|
[Obsolete("Use NetworkFeeMode instead")]
|
||||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||||
public bool? NetworkFeeDisabled
|
public bool? NetworkFeeDisabled
|
||||||
|
|||||||
14
BTCPayServer/Models/StoreViewModels/IntegrationsViewModel.cs
Normal file
14
BTCPayServer/Models/StoreViewModels/IntegrationsViewModel.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static BTCPayServer.Data.StoreBlob;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Models.StoreViewModels
|
||||||
|
{
|
||||||
|
public class IntegrationsViewModel
|
||||||
|
{
|
||||||
|
public ShopifyDataHolder Shopify { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,23 @@ namespace BTCPayServer.Services.Shopify
|
|||||||
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + bearer);
|
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + bearer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HttpRequestMessage createRequest(string shopNameInUrl, HttpMethod method, string action)
|
||||||
|
{
|
||||||
|
var url = $"https://{shopNameInUrl}.myshopify.com/admin/api/2020-07/" + action;
|
||||||
|
|
||||||
|
var req = new HttpRequestMessage(method, url);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> sendRequest(HttpRequestMessage req)
|
||||||
|
{
|
||||||
|
using var resp = await _httpClient.SendAsync(req);
|
||||||
|
|
||||||
|
var strResp = await resp.Content.ReadAsStringAsync();
|
||||||
|
return strResp;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<dynamic> TransactionsList(string orderId)
|
public async Task<dynamic> TransactionsList(string orderId)
|
||||||
{
|
{
|
||||||
var req = createRequest(_creds.ShopName, HttpMethod.Get, $"orders/{orderId}/transactions.json");
|
var req = createRequest(_creds.ShopName, HttpMethod.Get, $"orders/{orderId}/transactions.json");
|
||||||
@@ -58,21 +75,14 @@ namespace BTCPayServer.Services.Shopify
|
|||||||
return JObject.Parse(strResp);
|
return JObject.Parse(strResp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpRequestMessage createRequest(string shopNameInUrl, HttpMethod method, string action)
|
public async Task<int> OrdersCount()
|
||||||
{
|
{
|
||||||
var url = $"https://{shopNameInUrl}.myshopify.com/admin/api/2020-07/" + action;
|
var req = createRequest(_creds.ShopName, HttpMethod.Get, $"orders/count.json");
|
||||||
|
var strResp = await sendRequest(req);
|
||||||
|
|
||||||
var req = new HttpRequestMessage(method, url);
|
dynamic parsed = JObject.Parse(strResp);
|
||||||
|
|
||||||
return req;
|
return parsed.count;
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> sendRequest(HttpRequestMessage req)
|
|
||||||
{
|
|
||||||
using var resp = await _httpClient.SendAsync(req);
|
|
||||||
|
|
||||||
var strResp = await resp.Content.ReadAsStringAsync();
|
|
||||||
return strResp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
87
BTCPayServer/Views/Stores/Integrations.cshtml
Normal file
87
BTCPayServer/Views/Stores/Integrations.cshtml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
@using static BTCPayServer.Data.StoreBlob
|
||||||
|
@model IntegrationsViewModel
|
||||||
|
@{
|
||||||
|
Layout = "../Shared/_NavLayout.cshtml";
|
||||||
|
ViewData.SetActivePageAndTitle(StoreNavPages.Integrations, "Integrations");
|
||||||
|
}
|
||||||
|
|
||||||
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
|
@if (!ViewContext.ModelState.IsValid)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<form method="post">
|
||||||
|
<h4 class="mb-3">Shopify</h4>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Shopify.ShopName"></label>
|
||||||
|
<a href="https://docs.btcpayserver.org/Theme/#checkout-page-themes" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a>
|
||||||
|
<input asp-for="Shopify.ShopName" class="form-control" />
|
||||||
|
<span asp-validation-for="Shopify.ShopName" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Shopify.ApiKey"></label>
|
||||||
|
<a href="https://docs.btcpayserver.org/Theme/#checkout-page-themes" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a>
|
||||||
|
<input asp-for="Shopify.ApiKey" class="form-control" />
|
||||||
|
<span asp-validation-for="Shopify.ApiKey" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Shopify.Password"></label>
|
||||||
|
<a href="https://docs.btcpayserver.org/Theme/#checkout-page-themes" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a>
|
||||||
|
<input asp-for="Shopify.Password" class="form-control" />
|
||||||
|
<span asp-validation-for="Shopify.Password" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Shopify.SharedSecret"></label>
|
||||||
|
<a href="https://docs.btcpayserver.org/Theme/#checkout-page-themes" target="_blank"><span class="fa fa-question-circle-o" title="More information..."></span></a>
|
||||||
|
<input asp-for="Shopify.SharedSecret" class="form-control" />
|
||||||
|
<span asp-validation-for="Shopify.SharedSecret" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (Model.Shopify?.CredentialsValid == false)
|
||||||
|
{
|
||||||
|
<button name="command" type="submit" class="btn btn-primary" value="ShopifySaveCredentials">Save Credentials</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button name="command" type="submit" class="btn btn-error btn-sm" value="ShopifyClearCredentials">Clear Credentials</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Model.Shopify?.CredentialsValid == true)
|
||||||
|
{
|
||||||
|
var shopify = Model.Shopify;
|
||||||
|
<br /><br />
|
||||||
|
<h4 class="mb-3">Shopify Operations</h4>
|
||||||
|
|
||||||
|
if (!shopify.IntegratedAt.HasValue)
|
||||||
|
{
|
||||||
|
<button name="command" type="submit" class="btn btn-primary" value="ShopifyIntegrate">Integrate Shopify Order Paid Marking</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
Orders on <b>@shopify.ShopName</b>.myshopify.com will be marked as paid on successful invoice payment.
|
||||||
|
Started: @shopify.IntegratedAt.Value.ToBrowserDate()
|
||||||
|
</p>
|
||||||
|
<p></p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
@await Html.PartialAsync("_ValidationScriptsPartial")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user