btcpayserver/BTCPayServer/Services/PaymentRequests/PaymentRequestRepository.cs
Andrew Camilleri 022285806b
Form Builder (#4137)
* wip

* Cleanups

* UI updates

* Update UIFormsController.cs

* Make predefined forms usable statically

* Add support for pos app + forms

* pay request form rough support

* invoice form through receipt page

* Display form name in inherit from store setting

* Do not request additional forms on invoice from pay request

* fix up code

* move checkoutform id in checkout appearance outside of checkotu v2 toggle

* general fixes for form system

* fix pav bug

* UI updates

* Fix warnings in Form builder (#4331)

* Fix build warnings about string?

Enable nullable on UIFormsController.cs
Fixes CS8632 The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

* Clean up lack of space in injected services in Submit() of UIFormsController.cs

* Remove unused variables (CS0219) and assignment of nullable value to nullable type (CS8600)

* Cleanup double semicolons while we're at tit

* Fix: If reverse proxy wasn't well configured, and error message should have been displayed (#4322)

* fix monero issue

* Server Settings: Update Policies page (#4326)

Handles the multiple submit buttons on that page and closes #4319.

Contains some UI unifications with other pages and also shows the block explorers without needing to toggle the section via JS.

* Change confirmed to settled. (#4328)

* POS: Fix null pointer

Introduced in #4307, the referenced object needs to be `itemChoice` instead of `choice`.

* Add documentation link to plugins (#4329)

* Add documentation link to plugins

* Minor UI updates

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>

* Fix flaky test (#4330)

* Fix flaky test

* Update BTCPayServer/PayoutProcessors/BaseAutomatedPayoutProcessor.cs

Co-authored-by: d11n <mail@dennisreimann.de>

Co-authored-by: d11n <mail@dennisreimann.de>

* Remove invoice and store level form

* add form test

* fix migration for forms

* fix

* make pay request form submission redirect to invoice

* Refactor FormQuery to only be able to query single store and single form

* Put the Authorize at controller level on UIForms

* Fix warnings

* Fix ef request

* Fix query to forms, ensure no permission bypass

* Fix modify

* Remove storeId from step form

* Remove useless storeId parameter

* Hide custom form feature in UI

* Minor cleanups

* Remove custom form options from select for now

* More minor syntax cleanups

* Update test

* Add index - needs migration

* Refactoring: Use PostRedirect instead of TempData for data transfer

* Remove untested and unfinished code

* formResponse should be a JObject, not a string

* Fix case for Form type

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
Co-authored-by: JesterHodl <103882255+jesterhodl@users.noreply.github.com>
Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
Co-authored-by: Andreas Tasch <andy.tasch@gmail.com>
2022-11-25 10:42:55 +09:00

183 lines
6.6 KiB
C#

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Data;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Stores;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Services.PaymentRequests
{
public class PaymentRequestRepository
{
private readonly ApplicationDbContextFactory _ContextFactory;
private readonly InvoiceRepository _InvoiceRepository;
public PaymentRequestRepository(ApplicationDbContextFactory contextFactory, InvoiceRepository invoiceRepository)
{
_ContextFactory = contextFactory;
_InvoiceRepository = invoiceRepository;
}
public async Task<PaymentRequestData> CreateOrUpdatePaymentRequest(PaymentRequestData entity)
{
await using var context = _ContextFactory.CreateContext();
if (string.IsNullOrEmpty(entity.Id))
{
entity.Id = Guid.NewGuid().ToString();
await context.PaymentRequests.AddAsync(entity);
}
else
{
context.PaymentRequests.Update(entity);
}
await context.SaveChangesAsync();
return entity;
}
public async Task<PaymentRequestData> FindPaymentRequest(string id, string userId, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(id))
{
return null;
}
using var context = _ContextFactory.CreateContext();
var result = await context.PaymentRequests.Include(x => x.StoreData)
.Where(data =>
string.IsNullOrEmpty(userId) ||
(data.StoreData != null && data.StoreData.UserStores.Any(u => u.ApplicationUserId == userId)))
.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
return result;
}
public async Task<bool> IsPaymentRequestAdmin(string paymentRequestId, string userId)
{
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(paymentRequestId))
{
return false;
}
using var context = _ContextFactory.CreateContext();
return await context.PaymentRequests.Include(x => x.StoreData)
.AnyAsync(data =>
data.Id == paymentRequestId &&
(data.StoreData != null && data.StoreData.UserStores.Any(u => u.ApplicationUserId == userId)));
}
public async Task UpdatePaymentRequestStatus(string paymentRequestId, Client.Models.PaymentRequestData.PaymentRequestStatus status, CancellationToken cancellationToken = default)
{
using var context = _ContextFactory.CreateContext();
var invoiceData = await context.FindAsync<PaymentRequestData>(paymentRequestId);
if (invoiceData == null)
return;
invoiceData.Status = status;
await context.SaveChangesAsync(cancellationToken);
}
public async Task<PaymentRequestData[]> FindPaymentRequests(PaymentRequestQuery query, CancellationToken cancellationToken = default)
{
using var context = _ContextFactory.CreateContext();
var queryable = context.PaymentRequests.Include(data => data.StoreData).AsQueryable();
if (!query.IncludeArchived)
{
queryable = queryable.Where(data => !data.Archived);
}
if (!string.IsNullOrEmpty(query.StoreId))
{
queryable = queryable.Where(data =>
data.StoreDataId == query.StoreId);
}
if (query.Status != null && query.Status.Any())
{
queryable = queryable.Where(data =>
query.Status.Contains(data.Status));
}
if (query.Ids != null && query.Ids.Any())
{
queryable = queryable.Where(data =>
query.Ids.Contains(data.Id));
}
if (!string.IsNullOrEmpty(query.UserId))
{
queryable = queryable.Where(i =>
i.StoreData != null && i.StoreData.UserStores.Any(u => u.ApplicationUserId == query.UserId));
}
queryable = queryable.OrderByDescending(u => u.Created);
if (query.Skip.HasValue)
{
queryable = queryable.Skip(query.Skip.Value);
}
if (query.Count.HasValue)
{
queryable = queryable.Take(query.Count.Value);
}
var items = await queryable.ToArrayAsync(cancellationToken);
return items;
}
public async Task<InvoiceEntity[]> GetInvoicesForPaymentRequest(string paymentRequestId,
InvoiceQuery invoiceQuery = null)
{
if (invoiceQuery == null)
{
invoiceQuery = new InvoiceQuery();
}
invoiceQuery.OrderId = new[] { GetOrderIdForPaymentRequest(paymentRequestId) };
return (await _InvoiceRepository.GetInvoices(invoiceQuery))
.Where(i => i.InternalTags.Contains(GetInternalTag(paymentRequestId)))
.ToArray();
}
public static string GetOrderIdForPaymentRequest(string paymentRequestId)
{
return $"PAY_REQUEST_{paymentRequestId}";
}
public static string GetPaymentRequestIdFromOrderId(string invoiceOrderId)
{
if (string.IsNullOrEmpty(invoiceOrderId) ||
!invoiceOrderId.StartsWith("PAY_REQUEST_", StringComparison.InvariantCulture))
{
return null;
}
return invoiceOrderId.Replace("PAY_REQUEST_", "", StringComparison.InvariantCulture);
}
public static string GetInternalTag(string id)
{
return $"PAYREQ#{id}";
}
public static string[] GetPaymentIdsFromInternalTags(InvoiceEntity invoiceEntity)
{
return invoiceEntity.GetInternalTags("PAYREQ#");
}
}
public class PaymentRequestUpdated
{
public string PaymentRequestId { get; set; }
public PaymentRequestData Data { get; set; }
}
public class PaymentRequestQuery
{
public string StoreId { get; set; }
public bool IncludeArchived { get; set; } = true;
public Client.Models.PaymentRequestData.PaymentRequestStatus[] Status { get; set; }
public string UserId { get; set; }
public int? Skip { get; set; }
public int? Count { get; set; }
public string[] Ids { get; set; }
}
}