Rename paywall to payment

This commit is contained in:
Kieran 2022-09-07 15:52:40 +01:00
parent c3dbecca2a
commit af62bd74eb
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
40 changed files with 439 additions and 388 deletions

View File

@ -1,7 +1,7 @@
using System.Net;
using Microsoft.AspNetCore.Mvc;
using VoidCat.Model;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Files;
@ -12,16 +12,16 @@ public class DownloadController : Controller
{
private readonly FileStoreFactory _storage;
private readonly FileInfoManager _fileInfo;
private readonly IPaywallOrderStore _paywallOrders;
private readonly IPaymentOrderStore _paymentOrders;
private readonly ILogger<DownloadController> _logger;
public DownloadController(FileStoreFactory storage, ILogger<DownloadController> logger, FileInfoManager fileInfo,
IPaywallOrderStore paywall)
IPaymentOrderStore paymentOrderStore)
{
_storage = storage;
_logger = logger;
_fileInfo = fileInfo;
_paywallOrders = paywall;
_paymentOrders = paymentOrderStore;
}
[HttpOptions]
@ -45,7 +45,7 @@ public class DownloadController : Controller
var voidFile = await SetupDownload(gid);
if (voidFile == default) return;
var egressReq = new EgressRequest(gid, GetRanges(Request, (long)voidFile!.Metadata!.Size));
var egressReq = new EgressRequest(gid, GetRanges(Request, (long) voidFile!.Metadata!.Size));
if (egressReq.Ranges.Count() > 1)
{
_logger.LogWarning("Multi-range request not supported!");
@ -57,10 +57,10 @@ public class DownloadController : Controller
}
else if (egressReq.Ranges.Count() == 1)
{
Response.StatusCode = (int)HttpStatusCode.PartialContent;
Response.StatusCode = (int) HttpStatusCode.PartialContent;
if (egressReq.Ranges.Sum(a => a.Size) == 0)
{
Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
Response.StatusCode = (int) HttpStatusCode.RequestedRangeNotSatisfiable;
return;
}
}
@ -78,7 +78,7 @@ public class DownloadController : Controller
var preResult = await _storage.StartEgress(egressReq);
if (preResult.Redirect != null)
{
Response.StatusCode = (int)HttpStatusCode.Redirect;
Response.StatusCode = (int) HttpStatusCode.Redirect;
Response.Headers.Location = preResult.Redirect.ToString();
Response.ContentLength = 0;
return;
@ -99,13 +99,13 @@ public class DownloadController : Controller
return default;
}
// check paywall
if (meta.Paywall != default && meta.Paywall.Service != PaymentServices.None)
// check payment order
if (meta.Payment != default && meta.Payment.Service != PaymentServices.None)
{
var orderId = Request.Headers.GetHeader("V-OrderId") ?? Request.Query["orderId"];
if (!await IsOrderPaid(orderId))
{
Response.StatusCode = (int)HttpStatusCode.PaymentRequired;
Response.StatusCode = (int) HttpStatusCode.PaymentRequired;
return default;
}
}
@ -121,8 +121,8 @@ public class DownloadController : Controller
{
if (Guid.TryParse(orderId, out var oid))
{
var order = await _paywallOrders.Get(oid);
if (order?.Status == PaywallOrderStatus.Paid)
var order = await _paymentOrders.Get(oid);
if (order?.Status == PaymentOrderStatus.Paid)
{
return true;
}

View File

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.StaticFiles;
using Newtonsoft.Json;
using VoidCat.Model;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Files;
@ -15,22 +15,22 @@ namespace VoidCat.Controllers
{
private readonly FileStoreFactory _storage;
private readonly IFileMetadataStore _metadata;
private readonly IPaywallStore _paywall;
private readonly IPaywallFactory _paywallFactory;
private readonly IPaymentStore _payment;
private readonly IPaymentFactory _paymentFactory;
private readonly FileInfoManager _fileInfo;
private readonly IUserUploadsStore _userUploads;
private readonly IUserStore _userStore;
private readonly ITimeSeriesStatsReporter _timeSeriesStats;
private readonly VoidSettings _settings;
public UploadController(FileStoreFactory storage, IFileMetadataStore metadata, IPaywallStore paywall,
IPaywallFactory paywallFactory, FileInfoManager fileInfo, IUserUploadsStore userUploads,
public UploadController(FileStoreFactory storage, IFileMetadataStore metadata, IPaymentStore payment,
IPaymentFactory paymentFactory, FileInfoManager fileInfo, IUserUploadsStore userUploads,
ITimeSeriesStatsReporter timeSeriesStats, IUserStore userStore, VoidSettings settings)
{
_storage = storage;
_metadata = metadata;
_paywall = paywall;
_paywallFactory = paywallFactory;
_payment = payment;
_paymentFactory = paymentFactory;
_fileInfo = fileInfo;
_userUploads = userUploads;
_timeSeriesStats = timeSeriesStats;
@ -204,20 +204,20 @@ namespace VoidCat.Controllers
}
/// <summary>
/// Create a paywall order to pay
/// Create a payment order to pay
/// </summary>
/// <param name="id">File id</param>
/// <returns></returns>
[HttpGet]
[Route("{id}/paywall")]
public async ValueTask<PaywallOrder?> CreateOrder([FromRoute] string id)
[Route("{id}/payment")]
public async ValueTask<PaymentOrder?> CreateOrder([FromRoute] string id)
{
var gid = id.FromBase58Guid();
var file = await _fileInfo.Get(gid);
var config = await _paywall.Get(gid);
var config = await _payment.Get(gid);
var provider = await _paywallFactory.CreateProvider(config!.Service);
return await provider.CreateOrder(file!.Paywall!);
var provider = await _paymentFactory.CreateProvider(config!.Service);
return await provider.CreateOrder(file!.Payment!);
}
/// <summary>
@ -227,25 +227,25 @@ namespace VoidCat.Controllers
/// <param name="order">Order id</param>
/// <returns></returns>
[HttpGet]
[Route("{id}/paywall/{order:guid}")]
public async ValueTask<PaywallOrder?> GetOrderStatus([FromRoute] string id, [FromRoute] Guid order)
[Route("{id}/payment/{order:guid}")]
public async ValueTask<PaymentOrder?> GetOrderStatus([FromRoute] string id, [FromRoute] Guid order)
{
var gid = id.FromBase58Guid();
var config = await _paywall.Get(gid);
var config = await _payment.Get(gid);
var provider = await _paywallFactory.CreateProvider(config!.Service);
var provider = await _paymentFactory.CreateProvider(config!.Service);
return await provider.GetOrderStatus(order);
}
/// <summary>
/// Update the paywall config
/// Update the payment config
/// </summary>
/// <param name="id">File id</param>
/// <param name="req">Requested config to set on the file</param>
/// <returns></returns>
[HttpPost]
[Route("{id}/paywall")]
public async Task<IActionResult> SetPaywallConfig([FromRoute] string id, [FromBody] SetPaywallConfigRequest req)
[Route("{id}/payment")]
public async Task<IActionResult> SetPaymentConfig([FromRoute] string id, [FromBody] SetPaymentConfigRequest req)
{
var gid = id.FromBase58Guid();
var meta = await _metadata.Get<SecretVoidFileMeta>(gid);
@ -254,7 +254,7 @@ namespace VoidCat.Controllers
if (req.Strike != default)
{
await _paywall.Add(gid, new StrikePaywallConfig()
await _payment.Add(gid, new StrikePaymentConfig()
{
Service = PaymentServices.Strike,
Handle = req.Strike.Handle,
@ -265,7 +265,7 @@ namespace VoidCat.Controllers
}
// if none set, delete config
await _paywall.Delete(gid);
await _payment.Delete(gid);
return Ok();
}
@ -335,11 +335,11 @@ namespace VoidCat.Controllers
=> new(false, null, message);
}
public record SetPaywallConfigRequest
public record SetPaymentConfigRequest
{
[JsonConverter(typeof(Base58GuidConverter))]
public Guid EditSecret { get; init; }
public StrikePaywallConfig? Strike { get; init; }
public StrikePaymentConfig? Strike { get; init; }
}
}

View File

@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace VoidCat.Model.Payments;
/// <summary>
/// Money amount for payment orders
/// </summary>
/// <param name="Amount"></param>
/// <param name="Currency"></param>
public record PaymentMoney(decimal Amount, PaymentCurrencies Currency);
/// <summary>
/// Supported payment currencies
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum PaymentCurrencies : byte
{
BTC = 0,
USD = 1,
EUR = 2,
GBP = 3
}

View File

@ -1,9 +1,9 @@
namespace VoidCat.Model.Paywall;
namespace VoidCat.Model.Payments;
/// <summary>
/// Status of paywall order
/// Status of payment order
/// </summary>
public enum PaywallOrderStatus : byte
public enum PaymentOrderStatus : byte
{
/// <summary>
/// Invoice is not paid yet
@ -22,9 +22,9 @@ public enum PaywallOrderStatus : byte
}
/// <summary>
/// Base paywall order
/// Base payment order
/// </summary>
public class PaywallOrder
public class PaymentOrder
{
/// <summary>
/// Unique id of the order
@ -44,18 +44,18 @@ public class PaywallOrder
/// <summary>
/// The price of the order
/// </summary>
public PaywallMoney Price { get; init; } = null!;
public PaymentMoney Price { get; init; } = null!;
/// <summary>
/// Current status of the order
/// </summary>
public PaywallOrderStatus Status { get; set; }
public PaymentOrderStatus Status { get; set; }
}
/// <summary>
/// A paywall order lightning network invoice
/// A payment order lightning network invoice
/// </summary>
public class LightningPaywallOrder : PaywallOrder
public class LightningPaymentOrder : PaymentOrder
{
/// <summary>
/// Lightning invoice

View File

@ -0,0 +1,17 @@
namespace VoidCat.Model.Payments;
/// <summary>
/// Payment services supported by the system
/// </summary>
public enum PaymentServices
{
/// <summary>
/// No service
/// </summary>
None,
/// <summary>
/// Strike.me payment service
/// </summary>
Strike
}

View File

@ -0,0 +1,45 @@
namespace VoidCat.Model.Payments;
/// <summary>
/// Base payment config
/// </summary>
public abstract class PaymentConfig
{
/// <summary>
/// File this config is for
/// </summary>
public Guid File { get; init; }
/// <summary>
/// Service used to pay the payment
/// </summary>
public PaymentServices Service { get; init; } = PaymentServices.None;
/// <summary>
/// The cost for the payment to pass
/// </summary>
public PaymentMoney Cost { get; init; } = new(0m, PaymentCurrencies.BTC);
/// <summary>
/// If the payment is required
/// </summary>
public bool Required { get; init; } = true;
}
/// <inheritdoc />
public sealed class NoPaymentConfig : PaymentConfig
{
}
/// <summary>
/// Payment config for <see cref="PaymentServices.Strike"/> service
/// </summary>
/// <param name="Cost"></param>
public sealed class StrikePaymentConfig : PaymentConfig
{
/// <summary>
/// Strike username to pay to
/// </summary>
public string Handle { get; init; } = null!;
}

View File

@ -1,56 +0,0 @@
namespace VoidCat.Model.Paywall;
/// <summary>
/// Payment services supported by the system
/// </summary>
public enum PaymentServices
{
/// <summary>
/// No service
/// </summary>
None,
/// <summary>
/// Strike.me payment service
/// </summary>
Strike
}
/// <summary>
/// Base paywall config
/// </summary>
public abstract class PaywallConfig
{
/// <summary>
/// File this config is for
/// </summary>
public Guid File { get; init; }
/// <summary>
/// Service used to pay the paywall
/// </summary>
public PaymentServices Service { get; init; } = PaymentServices.None;
/// <summary>
/// The cost for the paywall to pass
/// </summary>
public PaywallMoney Cost { get; init; } = new(0m, PaywallCurrencies.BTC);
}
/// <inheritdoc />
public sealed class NoPaywallConfig : PaywallConfig
{
}
/// <summary>
/// Paywall config for <see cref="PaymentServices.Strike"/> service
/// </summary>
/// <param name="Cost"></param>
public sealed class StrikePaywallConfig : PaywallConfig
{
/// <summary>
/// Strike username to pay to
/// </summary>
public string Handle { get; init; } = null!;
}

View File

@ -1,14 +0,0 @@
using System.Text.Json.Serialization;
namespace VoidCat.Model.Paywall;
public record PaywallMoney(decimal Amount, PaywallCurrencies Currency);
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum PaywallCurrencies : byte
{
BTC = 0,
USD = 1,
EUR = 2,
GBP = 3
}

View File

@ -1,5 +1,5 @@
using Newtonsoft.Json;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
namespace VoidCat.Model
{
@ -17,9 +17,9 @@ namespace VoidCat.Model
public TMeta? Metadata { get; init; }
/// <summary>
/// Optional paywall config
/// Optional payment config
/// </summary>
public PaywallConfig? Paywall { get; init; }
public PaymentConfig? Payment { get; init; }
/// <summary>
/// User profile that uploaded the file

View File

@ -0,0 +1,16 @@
using VoidCat.Model.Payments;
namespace VoidCat.Services.Abstractions;
/// <summary>
/// Factory class to access service provider implementations
/// </summary>
public interface IPaymentFactory
{
/// <summary>
/// Create provider handler for specified service type
/// </summary>
/// <param name="svc"></param>
/// <returns></returns>
ValueTask<IPaymentProvider> CreateProvider(PaymentServices svc);
}

View File

@ -1,11 +1,11 @@
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
namespace VoidCat.Services.Abstractions;
/// <summary>
/// Paywall order store
/// Payment order store
/// </summary>
public interface IPaywallOrderStore : IBasicStore<PaywallOrder>
public interface IPaymentOrderStore : IBasicStore<PaymentOrder>
{
/// <summary>
/// Update the status of an order
@ -13,5 +13,5 @@ public interface IPaywallOrderStore : IBasicStore<PaywallOrder>
/// <param name="order"></param>
/// <param name="status"></param>
/// <returns></returns>
ValueTask UpdateStatus(Guid order, PaywallOrderStatus status);
ValueTask UpdateStatus(Guid order, PaymentOrderStatus status);
}

View File

@ -1,23 +1,23 @@
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
namespace VoidCat.Services.Abstractions;
/// <summary>
/// Provider to generate orders for a specific config
/// </summary>
public interface IPaywallProvider
public interface IPaymentProvider
{
/// <summary>
/// Create an order with the provider
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
ValueTask<PaywallOrder?> CreateOrder(PaywallConfig file);
ValueTask<PaymentOrder?> CreateOrder(PaymentConfig file);
/// <summary>
/// Get the status of an existing order with the provider
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
ValueTask<PaywallOrder?> GetOrderStatus(Guid id);
ValueTask<PaymentOrder?> GetOrderStatus(Guid id);
}

View File

@ -0,0 +1,10 @@
using VoidCat.Model.Payments;
namespace VoidCat.Services.Abstractions;
/// <summary>
/// Store for payment configs
/// </summary>
public interface IPaymentStore : IBasicStore<PaymentConfig>
{
}

View File

@ -1,8 +0,0 @@
using VoidCat.Model.Paywall;
namespace VoidCat.Services.Abstractions;
public interface IPaywallFactory
{
ValueTask<IPaywallProvider> CreateProvider(PaymentServices svc);
}

View File

@ -1,10 +0,0 @@
using VoidCat.Model.Paywall;
namespace VoidCat.Services.Abstractions;
/// <summary>
/// Store for paywall configs
/// </summary>
public interface IPaywallStore : IBasicStore<PaywallConfig>
{
}

View File

@ -10,17 +10,17 @@ namespace VoidCat.Services.Files;
public sealed class FileInfoManager
{
private readonly IFileMetadataStore _metadataStore;
private readonly IPaywallStore _paywallStore;
private readonly IPaymentStore _paymentStore;
private readonly IStatsReporter _statsReporter;
private readonly IUserStore _userStore;
private readonly IVirusScanStore _virusScanStore;
private readonly IUserUploadsStore _userUploadsStore;
public FileInfoManager(IFileMetadataStore metadataStore, IPaywallStore paywallStore, IStatsReporter statsReporter,
public FileInfoManager(IFileMetadataStore metadataStore, IPaymentStore paymentStore, IStatsReporter statsReporter,
IUserStore userStore, IVirusScanStore virusScanStore, IUserUploadsStore userUploadsStore)
{
_metadataStore = metadataStore;
_paywallStore = paywallStore;
_paymentStore = paymentStore;
_statsReporter = statsReporter;
_userStore = userStore;
_virusScanStore = virusScanStore;
@ -75,7 +75,7 @@ public sealed class FileInfoManager
public async ValueTask Delete(Guid id)
{
await _metadataStore.Delete(id);
await _paywallStore.Delete(id);
await _paymentStore.Delete(id);
await _statsReporter.Delete(id);
await _virusScanStore.Delete(id);
}
@ -84,11 +84,11 @@ public sealed class FileInfoManager
where TMeta : VoidFileMeta where TFile : VoidFile<TMeta>, new()
{
var meta = _metadataStore.Get<TMeta>(id);
var paywall = _paywallStore.Get(id);
var payment = _paymentStore.Get(id);
var bandwidth = _statsReporter.GetBandwidth(id);
var virusScan = _virusScanStore.GetByFile(id);
var uploader = _userUploadsStore.Uploader(id);
await Task.WhenAll(meta.AsTask(), paywall.AsTask(), bandwidth.AsTask(), virusScan.AsTask(), uploader.AsTask());
await Task.WhenAll(meta.AsTask(), payment.AsTask(), bandwidth.AsTask(), virusScan.AsTask(), uploader.AsTask());
if (meta.Result == default) return default;
var user = uploader.Result.HasValue ? await _userStore.Get<PublicVoidUser>(uploader.Result.Value) : null;
@ -97,7 +97,7 @@ public sealed class FileInfoManager
{
Id = id,
Metadata = meta.Result,
Paywall = paywall.Result,
Payment = payment.Result,
Bandwidth = bandwidth.Result,
Uploader = user?.Flags.HasFlag(VoidUserFlags.PublicProfile) == true ? user : null,
VirusScan = virusScan.Result

View File

@ -0,0 +1,27 @@
using FluentMigrator;
namespace VoidCat.Services.Migrations.Database;
[Migration(20220908_1527)]
public class PaywallToPayments : Migration
{
public override void Up()
{
Rename.Table("Paywall")
.To("Payment");
Rename.Table("PaywallOrder")
.To("PaymentOrder");
Rename.Table("PaywallStrike")
.To("PaymentStrike");
Rename.Table("PaywallOrderLightning")
.To("PaymentOrderLightning");
}
public override void Down()
{
// yolo
}
}

View File

@ -3,7 +3,7 @@ using Newtonsoft.Json;
using VoidCat.Model;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Files;
using VoidCat.Services.Paywall;
using VoidCat.Services.Payment;
using VoidCat.Services.Users;
namespace VoidCat.Services.Migrations;
@ -15,20 +15,20 @@ public class MigrateToPostgres : IMigration
private readonly VoidSettings _settings;
private readonly IFileMetadataStore _fileMetadata;
private readonly ICache _cache;
private readonly IPaywallStore _paywallStore;
private readonly IPaymentStore _paymentStore;
private readonly IUserStore _userStore;
private readonly IUserUploadsStore _userUploads;
private readonly FileStoreFactory _fileStore;
public MigrateToPostgres(VoidSettings settings, ILogger<MigrateToPostgres> logger, IFileMetadataStore fileMetadata,
ICache cache, IPaywallStore paywallStore, IUserStore userStore, IUserUploadsStore userUploads,
ICache cache, IPaymentStore paymentStore, IUserStore userStore, IUserUploadsStore userUploads,
FileStoreFactory fileStore)
{
_logger = logger;
_settings = settings;
_fileMetadata = fileMetadata;
_cache = cache;
_paywallStore = paywallStore;
_paymentStore = paymentStore;
_userStore = userStore;
_userUploads = userUploads;
_fileStore = fileStore;
@ -99,7 +99,7 @@ public class MigrateToPostgres : IMigration
private async Task MigratePaywall()
{
var cachePaywallStore = new CachePaywallStore(_cache);
var cachePaywallStore = new CachePaymentStore(_cache);
var files = await _fileMetadata.ListFiles<VoidFileMeta>(new(0, int.MaxValue));
await foreach (var file in files.Results)
@ -109,7 +109,7 @@ public class MigrateToPostgres : IMigration
var old = await cachePaywallStore.Get(file.Id);
if (old != default)
{
await _paywallStore.Add(file.Id, old);
await _paymentStore.Add(file.Id, old);
_logger.LogInformation("Migrated paywall config for {File}", file.Id);
}
}

View File

@ -0,0 +1,26 @@
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Payment;
/// <inheritdoc cref="IPaymentOrderStore"/>
public class CachePaymentOrderStore : BasicCacheStore<PaymentOrder>, IPaymentOrderStore
{
public CachePaymentOrderStore(ICache cache) : base(cache)
{
}
/// <inheritdoc />
public async ValueTask UpdateStatus(Guid order, PaymentOrderStatus status)
{
var old = await Get(order);
if (old == default) return;
old.Status = status;
await Add(order, old);
}
/// <inheritdoc />
protected override string MapKey(Guid id) => $"payment:order:{id}";
}

View File

@ -0,0 +1,28 @@
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Payment;
/// <inheritdoc cref="IPaymentStore"/>
public class CachePaymentStore : BasicCacheStore<PaymentConfig>, IPaymentStore
{
public CachePaymentStore(ICache database)
: base(database)
{
}
/// <inheritdoc />
public override async ValueTask<PaymentConfig?> Get(Guid id)
{
var cfg = await Cache.Get<NoPaymentConfig>(MapKey(id));
return cfg?.Service switch
{
PaymentServices.None => cfg,
PaymentServices.Strike => await Cache.Get<StrikePaymentConfig>(MapKey(id)),
_ => default
};
}
/// <inheritdoc />
protected override string MapKey(Guid id) => $"payment:config:{id}";
}

View File

@ -0,0 +1,23 @@
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Payment;
public class PaymentFactory : IPaymentFactory
{
private readonly IServiceProvider _services;
public PaymentFactory(IServiceProvider services)
{
_services = services;
}
public ValueTask<IPaymentProvider> CreateProvider(PaymentServices svc)
{
return ValueTask.FromResult<IPaymentProvider>(svc switch
{
PaymentServices.Strike => _services.GetRequiredService<StrikePaymentProvider>(),
_ => throw new ArgumentException("Must have a payment config", nameof(svc))
});
}
}

View File

@ -0,0 +1,32 @@
using VoidCat.Model;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Strike;
namespace VoidCat.Services.Payment;
public static class PaymentStartup
{
/// <summary>
/// Add services required to use payment functions
/// </summary>
/// <param name="services"></param>
/// <param name="settings"></param>
public static void AddPaymentServices(this IServiceCollection services, VoidSettings settings)
{
services.AddTransient<IPaymentFactory, PaymentFactory>();
if (settings.HasPostgres())
{
services.AddTransient<IPaymentStore, PostgresPaymentStore>();
services.AddTransient<IPaymentOrderStore, PostgresPaymentOrderStore>();
}
else
{
services.AddTransient<IPaymentStore, CachePaymentStore>();
services.AddTransient<IPaymentOrderStore, CachePaymentOrderStore>();
}
// strike
services.AddTransient<StrikeApi>();
services.AddTransient<StrikePaymentProvider>();
}
}

View File

@ -1,33 +1,33 @@
using Dapper;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Paywall;
namespace VoidCat.Services.Payment;
/// <inheritdoc />
public class PostgresPaywallOrderStore : IPaywallOrderStore
public class PostgresPaymentOrderStore : IPaymentOrderStore
{
private readonly PostgresConnectionFactory _connection;
public PostgresPaywallOrderStore(PostgresConnectionFactory connection)
public PostgresPaymentOrderStore(PostgresConnectionFactory connection)
{
_connection = connection;
}
/// <inheritdoc />
public async ValueTask<PaywallOrder?> Get(Guid id)
public async ValueTask<PaymentOrder?> Get(Guid id)
{
await using var conn = await _connection.Get();
var order = await conn.QuerySingleOrDefaultAsync<DtoPaywallOrder>(
@"select * from ""PaywallOrder"" where ""Id"" = :id", new {id});
var order = await conn.QuerySingleOrDefaultAsync<DtoPaymentOrder>(
@"select * from ""PaymentOrder"" where ""Id"" = :id", new {id});
if (order.Service is PaymentServices.Strike)
{
var lnDetails = await conn.QuerySingleAsync<LightningPaywallOrder>(
@"select * from ""PaywallOrderLightning"" where ""Order"" = :id", new
var lnDetails = await conn.QuerySingleAsync<LightningPaymentOrder>(
@"select * from ""PaymentOrderLightning"" where ""Order"" = :id", new
{
id = order.Id
});
return new LightningPaywallOrder
return new LightningPaymentOrder
{
Id = order.Id,
File = order.File,
@ -43,18 +43,18 @@ public class PostgresPaywallOrderStore : IPaywallOrderStore
}
/// <inheritdoc />
public ValueTask<IReadOnlyList<PaywallOrder>> Get(Guid[] ids)
public ValueTask<IReadOnlyList<PaymentOrder>> Get(Guid[] ids)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public async ValueTask Add(Guid id, PaywallOrder obj)
public async ValueTask Add(Guid id, PaymentOrder obj)
{
await using var conn = await _connection.Get();
await using var txn = await conn.BeginTransactionAsync();
await conn.ExecuteAsync(
@"insert into ""PaywallOrder""(""Id"", ""File"", ""Service"", ""Currency"", ""Amount"", ""Status"")
@"insert into ""PaymentOrder""(""Id"", ""File"", ""Service"", ""Currency"", ""Amount"", ""Status"")
values(:id, :file, :service, :currency, :amt, :status)",
new
{
@ -66,10 +66,10 @@ values(:id, :file, :service, :currency, :amt, :status)",
status = (int) obj.Status
});
if (obj is LightningPaywallOrder ln)
if (obj is LightningPaymentOrder ln)
{
await conn.ExecuteAsync(
@"insert into ""PaywallOrderLightning""(""Order"", ""Invoice"", ""Expire"") values(:order, :invoice, :expire)",
@"insert into ""PaymentOrderLightning""(""Order"", ""Invoice"", ""Expire"") values(:order, :invoice, :expire)",
new
{
order = id,
@ -85,20 +85,20 @@ values(:id, :file, :service, :currency, :amt, :status)",
public async ValueTask Delete(Guid id)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(@"delete from ""PaywallOrder"" where ""Id"" = :id", new {id});
await conn.ExecuteAsync(@"delete from ""PaymentOrder"" where ""Id"" = :id", new {id});
}
/// <inheritdoc />
public async ValueTask UpdateStatus(Guid order, PaywallOrderStatus status)
public async ValueTask UpdateStatus(Guid order, PaymentOrderStatus status)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(@"update ""PaywallOrder"" set ""Status"" = :status where ""Id"" = :id",
await conn.ExecuteAsync(@"update ""PaymentOrder"" set ""Status"" = :status where ""Id"" = :id",
new {id = order, status = (int) status});
}
private sealed class DtoPaywallOrder : PaywallOrder
private sealed class DtoPaymentOrder : PaymentOrder
{
public PaywallCurrencies Currency { get; init; }
public PaymentCurrencies Currency { get; init; }
public decimal Amount { get; init; }
}
}

View File

@ -1,25 +1,25 @@
using Dapper;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Paywall;
namespace VoidCat.Services.Payment;
/// <inheritdoc />
public sealed class PostgresPaywallStore : IPaywallStore
public sealed class PostgresPaymentStore : IPaymentStore
{
private readonly PostgresConnectionFactory _connection;
public PostgresPaywallStore(PostgresConnectionFactory connection)
public PostgresPaymentStore(PostgresConnectionFactory connection)
{
_connection = connection;
}
/// <inheritdoc />
public async ValueTask<PaywallConfig?> Get(Guid id)
public async ValueTask<PaymentConfig?> Get(Guid id)
{
await using var conn = await _connection.Get();
var svc = await conn.QuerySingleOrDefaultAsync<DtoPaywallConfig>(
@"select * from ""Paywall"" where ""File"" = :file", new {file = id});
var svc = await conn.QuerySingleOrDefaultAsync<DtoPaymentConfig>(
@"select * from ""Payment"" where ""File"" = :file", new {file = id});
if (svc != default)
{
switch (svc.Service)
@ -28,8 +28,8 @@ public sealed class PostgresPaywallStore : IPaywallStore
{
var handle =
await conn.ExecuteScalarAsync<string>(
@"select ""Handle"" from ""PaywallStrike"" where ""File"" = :file", new {file = id});
return new StrikePaywallConfig
@"select ""Handle"" from ""PaymentStrike"" where ""File"" = :file", new {file = id});
return new StrikePaymentConfig
{
Cost = new(svc.Amount, svc.Currency),
File = svc.File,
@ -44,18 +44,18 @@ public sealed class PostgresPaywallStore : IPaywallStore
}
/// <inheritdoc />
public ValueTask<IReadOnlyList<PaywallConfig>> Get(Guid[] ids)
public ValueTask<IReadOnlyList<PaymentConfig>> Get(Guid[] ids)
{
throw new NotImplementedException();
}
/// <inheritdoc />
public async ValueTask Add(Guid id, PaywallConfig obj)
public async ValueTask Add(Guid id, PaymentConfig obj)
{
await using var conn = await _connection.Get();
await using var txn = await conn.BeginTransactionAsync();
await conn.ExecuteAsync(
@"insert into ""Paywall""(""File"", ""Service"", ""Amount"", ""Currency"") values(:file, :service, :amount, :currency)
@"insert into ""Payment""(""File"", ""Service"", ""Amount"", ""Currency"") values(:file, :service, :amount, :currency)
on conflict(""File"") do update set ""Service"" = :service, ""Amount"" = :amount, ""Currency"" = :currency",
new
{
@ -65,9 +65,9 @@ on conflict(""File"") do update set ""Service"" = :service, ""Amount"" = :amount
currency = obj.Cost.Currency
});
if (obj is StrikePaywallConfig sc)
if (obj is StrikePaymentConfig sc)
{
await conn.ExecuteAsync(@"insert into ""PaywallStrike""(""File"", ""Handle"") values(:file, :handle)
await conn.ExecuteAsync(@"insert into ""PaymentStrike""(""File"", ""Handle"") values(:file, :handle)
on conflict(""File"") do update set ""Handle"" = :handle", new
{
file = id,
@ -82,12 +82,12 @@ on conflict(""File"") do update set ""Handle"" = :handle", new
public async ValueTask Delete(Guid id)
{
await using var conn = await _connection.Get();
await conn.ExecuteAsync(@"delete from ""Paywall"" where ""File"" = :file", new {file = id});
await conn.ExecuteAsync(@"delete from ""Payment"" where ""File"" = :file", new {file = id});
}
private sealed class DtoPaywallConfig : PaywallConfig
private sealed class DtoPaymentConfig : PaymentConfig
{
public PaywallCurrencies Currency { get; init; }
public PaymentCurrencies Currency { get; init; }
public decimal Amount { get; init; }
}
}

View File

@ -1,19 +1,19 @@
using System.Globalization;
using VoidCat.Model;
using VoidCat.Model.Paywall;
using VoidCat.Model.Payments;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Strike;
namespace VoidCat.Services.Paywall;
namespace VoidCat.Services.Payment;
/// <inheritdoc />
public class StrikePaywallProvider : IPaywallProvider
public class StrikePaymentProvider : IPaymentProvider
{
private readonly ILogger<StrikePaywallProvider> _logger;
private readonly ILogger<StrikePaymentProvider> _logger;
private readonly StrikeApi _strike;
private readonly IPaywallOrderStore _orderStore;
private readonly IPaymentOrderStore _orderStore;
public StrikePaywallProvider(ILogger<StrikePaywallProvider> logger, StrikeApi strike, IPaywallOrderStore orderStore)
public StrikePaymentProvider(ILogger<StrikePaymentProvider> logger, StrikeApi strike, IPaymentOrderStore orderStore)
{
_logger = logger;
_strike = strike;
@ -21,9 +21,9 @@ public class StrikePaywallProvider : IPaywallProvider
}
/// <inheritdoc />
public async ValueTask<PaywallOrder?> CreateOrder(PaywallConfig config)
public async ValueTask<PaymentOrder?> CreateOrder(PaymentConfig config)
{
IsStrikePaywall(config, out var strikeConfig);
IsStrikePayment(config, out var strikeConfig);
_logger.LogInformation("Generating invoice for {Currency} {Amount}", config.Cost.Currency, config.Cost.Amount);
var currency = MapCurrency(strikeConfig.Cost.Currency);
@ -57,13 +57,13 @@ public class StrikePaywallProvider : IPaywallProvider
var quote = await _strike.GetInvoiceQuote(invoice.InvoiceId);
if (quote != default)
{
var order = new LightningPaywallOrder
var order = new LightningPaymentOrder
{
Id = invoice.InvoiceId,
File = config.File,
Service = PaymentServices.Strike,
Price = config.Cost,
Status = PaywallOrderStatus.Unpaid,
Status = PaymentOrderStatus.Unpaid,
Invoice = quote.LnInvoice!,
Expire = DateTime.SpecifyKind(quote.Expiration.DateTime, DateTimeKind.Utc)
};
@ -80,10 +80,10 @@ public class StrikePaywallProvider : IPaywallProvider
}
/// <inheritdoc />
public async ValueTask<PaywallOrder?> GetOrderStatus(Guid id)
public async ValueTask<PaymentOrder?> GetOrderStatus(Guid id)
{
var order = await _orderStore.Get(id);
if (order is {Status: PaywallOrderStatus.Paid or PaywallOrderStatus.Expired}) return order;
if (order is {Status: PaymentOrderStatus.Paid or PaymentOrderStatus.Expired}) return order;
var providerOrder = await _strike.GetInvoice(id);
if (providerOrder != default)
@ -104,44 +104,44 @@ public class StrikePaywallProvider : IPaywallProvider
return default;
}
private PaywallOrderStatus MapStatus(InvoiceState providerOrderState)
private PaymentOrderStatus MapStatus(InvoiceState providerOrderState)
=> providerOrderState switch
{
InvoiceState.UNPAID => PaywallOrderStatus.Unpaid,
InvoiceState.PENDING => PaywallOrderStatus.Unpaid,
InvoiceState.PAID => PaywallOrderStatus.Paid,
InvoiceState.CANCELLED => PaywallOrderStatus.Expired,
InvoiceState.UNPAID => PaymentOrderStatus.Unpaid,
InvoiceState.PENDING => PaymentOrderStatus.Unpaid,
InvoiceState.PAID => PaymentOrderStatus.Paid,
InvoiceState.CANCELLED => PaymentOrderStatus.Expired,
_ => throw new ArgumentOutOfRangeException(nameof(providerOrderState), providerOrderState, null)
};
private static Currencies MapCurrency(PaywallCurrencies c)
private static Currencies MapCurrency(PaymentCurrencies c)
=> c switch
{
PaywallCurrencies.BTC => Currencies.BTC,
PaywallCurrencies.USD => Currencies.USD,
PaywallCurrencies.EUR => Currencies.EUR,
PaywallCurrencies.GBP => Currencies.GBP,
PaymentCurrencies.BTC => Currencies.BTC,
PaymentCurrencies.USD => Currencies.USD,
PaymentCurrencies.EUR => Currencies.EUR,
PaymentCurrencies.GBP => Currencies.GBP,
_ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
};
private static PaywallCurrencies MapCurrency(Currencies c)
private static PaymentCurrencies MapCurrency(Currencies c)
=> c switch
{
Currencies.BTC => PaywallCurrencies.BTC,
Currencies.USD => PaywallCurrencies.USD,
Currencies.USDT => PaywallCurrencies.USD,
Currencies.EUR => PaywallCurrencies.EUR,
Currencies.GBP => PaywallCurrencies.GBP,
Currencies.BTC => PaymentCurrencies.BTC,
Currencies.USD => PaymentCurrencies.USD,
Currencies.USDT => PaymentCurrencies.USD,
Currencies.EUR => PaymentCurrencies.EUR,
Currencies.GBP => PaymentCurrencies.GBP,
_ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
};
private static void IsStrikePaywall(PaywallConfig? cfg, out StrikePaywallConfig strikeConfig)
private static void IsStrikePayment(PaymentConfig? cfg, out StrikePaymentConfig strikeConfig)
{
if (cfg?.Service != PaymentServices.Strike)
{
throw new ArgumentException("Must be strike paywall");
throw new ArgumentException("Must be strike Payment");
}
strikeConfig = (cfg as StrikePaywallConfig)!;
strikeConfig = (cfg as StrikePaymentConfig)!;
}
}

View File

@ -1,26 +0,0 @@
using VoidCat.Model.Paywall;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Paywall;
/// <inheritdoc cref="IPaywallOrderStore"/>
public class CachePaywallOrderStore : BasicCacheStore<PaywallOrder>, IPaywallOrderStore
{
public CachePaywallOrderStore(ICache cache) : base(cache)
{
}
/// <inheritdoc />
public async ValueTask UpdateStatus(Guid order, PaywallOrderStatus status)
{
var old = await Get(order);
if (old == default) return;
old.Status = status;
await Add(order, old);
}
/// <inheritdoc />
protected override string MapKey(Guid id) => $"paywall:order:{id}";
}

View File

@ -1,28 +0,0 @@
using VoidCat.Model.Paywall;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Paywall;
/// <inheritdoc cref="IPaywallStore"/>
public class CachePaywallStore : BasicCacheStore<PaywallConfig>, IPaywallStore
{
public CachePaywallStore(ICache database)
: base(database)
{
}
/// <inheritdoc />
public override async ValueTask<PaywallConfig?> Get(Guid id)
{
var cfg = await Cache.Get<NoPaywallConfig>(MapKey(id));
return cfg?.Service switch
{
PaymentServices.None => cfg,
PaymentServices.Strike => await Cache.Get<StrikePaywallConfig>(MapKey(id)),
_ => default
};
}
/// <inheritdoc />
protected override string MapKey(Guid id) => $"paywall:config:{id}";
}

View File

@ -1,23 +0,0 @@
using VoidCat.Model.Paywall;
using VoidCat.Services.Abstractions;
namespace VoidCat.Services.Paywall;
public class PaywallFactory : IPaywallFactory
{
private readonly IServiceProvider _services;
public PaywallFactory(IServiceProvider services)
{
_services = services;
}
public ValueTask<IPaywallProvider> CreateProvider(PaymentServices svc)
{
return ValueTask.FromResult<IPaywallProvider>(svc switch
{
PaymentServices.Strike => _services.GetRequiredService<StrikePaywallProvider>(),
_ => throw new ArgumentException("Must have a paywall config", nameof(svc))
});
}
}

View File

@ -1,32 +0,0 @@
using VoidCat.Model;
using VoidCat.Services.Abstractions;
using VoidCat.Services.Strike;
namespace VoidCat.Services.Paywall;
public static class PaywallStartup
{
/// <summary>
/// Add services required to use paywall functions
/// </summary>
/// <param name="services"></param>
/// <param name="settings"></param>
public static void AddPaywallServices(this IServiceCollection services, VoidSettings settings)
{
services.AddTransient<IPaywallFactory, PaywallFactory>();
if (settings.HasPostgres())
{
services.AddTransient<IPaywallStore, PostgresPaywallStore>();
services.AddTransient<IPaywallOrderStore, PostgresPaywallOrderStore>();
}
else
{
services.AddTransient<IPaywallStore, CachePaywallStore>();
services.AddTransient<IPaywallOrderStore, CachePaywallOrderStore>();
}
// strike
services.AddTransient<StrikeApi>();
services.AddTransient<StrikePaywallProvider>();
}
}

View File

@ -18,7 +18,7 @@ using VoidCat.Services.Captcha;
using VoidCat.Services.Files;
using VoidCat.Services.InMemory;
using VoidCat.Services.Migrations;
using VoidCat.Services.Paywall;
using VoidCat.Services.Payment;
using VoidCat.Services.Redis;
using VoidCat.Services.Stats;
using VoidCat.Services.Users;
@ -66,7 +66,7 @@ public static class VoidStartup
{
services.AddStorage(voidSettings);
services.AddMetrics(voidSettings);
services.AddPaywallServices(voidSettings);
services.AddPaymentServices(voidSettings);
services.AddUserServices(voidSettings);
services.AddVirusScanner(voidSettings);
services.AddCaptcha(voidSettings);

View File

@ -33,9 +33,9 @@ export function useApi() {
Api: {
info: () => getJson("GET", "/info"),
fileInfo: (id) => getJson("GET", `/upload/${id}`, undefined, auth),
setPaywallConfig: (id, cfg) => getJson("POST", `/upload/${id}/paywall`, cfg, auth),
createOrder: (id) => getJson("GET", `/upload/${id}/paywall`),
getOrder: (file, order) => getJson("GET", `/upload/${file}/paywall/${order}`),
setPaymentConfig: (id, cfg) => getJson("POST", `/upload/${id}/payment`, cfg, auth),
createOrder: (id) => getJson("GET", `/upload/${id}/payment`),
getOrder: (file, order) => getJson("GET", `/upload/${file}/payment/${order}`),
login: (username, password, captcha) => getJson("POST", `/auth/login`, {username, password, captcha}),
register: (username, password, captcha) => getJson("POST", `/auth/register`, {username, password, captcha}),
getUser: (id) => getJson("GET", `/user/${id}`, undefined, auth),

View File

@ -37,19 +37,19 @@ export const ZiB = Math.pow(1024, 7);
*/
export const YiB = Math.pow(1024, 8);
export const PaywallCurrencies = {
export const PaymentCurrencies = {
BTC: 0,
USD: 1,
EUR: 2,
GBP: 3
}
export const PaywallServices = {
export const PaymentServices = {
None: 0,
Strike: 1
}
export const PaywallOrderState = {
export const PaymentOrderState = {
Unpaid: 0,
Paid: 1,
Expired: 2

View File

@ -1,7 +1,7 @@
import {useState} from "react";
import {StrikePaywallConfig} from "./StrikePaywallConfig";
import {NoPaywallConfig} from "./NoPaywallConfig";
import {StrikePaymentConfig} from "./StrikePaymentConfig";
import {NoPaymentConfig} from "./NoPaymentConfig";
import {useApi} from "./Api";
import "./FileEdit.css";
import {useSelector} from "react-redux";
@ -13,7 +13,7 @@ export function FileEdit(props) {
const file = props.file;
const meta = file.metadata;
const profile = useSelector(state => state.login.profile);
const [paywall, setPaywall] = useState(file.paywall?.service);
const [payment, setPayment] = useState(file.payment?.service);
const [name, setName] = useState(meta?.name);
const [description, setDescription] = useState(meta?.description);
const [expiry, setExpiry] = useState(meta?.expires === undefined || meta?.expires === null ? null : moment(meta?.expires).unix() * 1000);
@ -26,7 +26,7 @@ export function FileEdit(props) {
}
async function saveConfig(cfg) {
let req = await Api.setPaywallConfig(file.id, cfg);
let req = await Api.setPaymentConfig(file.id, cfg);
return req.ok;
}
@ -40,13 +40,13 @@ export function FileEdit(props) {
await Api.updateMetadata(file.id, meta);
}
function renderPaywallConfig() {
switch (paywall) {
function renderPaymentConfig() {
switch (payment) {
case 0: {
return <NoPaywallConfig privateFile={privateFile} onSaveConfig={saveConfig}/>;
return <NoPaymentConfig privateFile={privateFile} onSaveConfig={saveConfig}/>;
}
case 1: {
return <StrikePaywallConfig file={file} privateFile={privateFile} onSaveConfig={saveConfig}/>
return <StrikePaymentConfig file={file} privateFile={privateFile} onSaveConfig={saveConfig}/>
}
}
return null;
@ -81,13 +81,13 @@ export function FileEdit(props) {
<VoidButton onClick={(e) => saveMeta()} options={{showSuccess: true}}>Save</VoidButton>
</div>
<div className="flx-1">
<h3>Paywall Config</h3>
<h3>Payment Config</h3>
Type:
<select onChange={(e) => setPaywall(parseInt(e.target.value))} value={paywall}>
<select onChange={(e) => setPayment(parseInt(e.target.value))} value={payment}>
<option value={0}>None</option>
<option value={1}>Strike</option>
</select>
{renderPaywallConfig()}
{renderPaymentConfig()}
</div>
</div>
);

View File

@ -1,4 +1,4 @@
.paywall {
.payment {
text-align: center;
border: 1px solid lightgreen;
padding: 10px;

View File

@ -1,16 +1,16 @@
import "./FilePaywall.css";
import "./FilePayment.css";
import {FormatCurrency} from "./Util";
import {PaywallServices} from "./Const";
import {PaymentServices} from "./Const";
import {useState} from "react";
import {LightningPaywall} from "./LightningPaywall";
import {LightningPayment} from "./LightningPayment";
import {useApi} from "./Api";
import {VoidButton} from "./VoidButton";
export function FilePaywall(props) {
export function FilePayment(props) {
const {Api} = useApi();
const file = props.file;
const pw = file.paywall;
const paywallKey = `paywall-${file.id}`;
const pw = file.payment;
const paymentKey = `payment-${file.id}`;
const onPaid = props.onPaid;
const [order, setOrder] = useState();
@ -27,7 +27,7 @@ export function FilePaywall(props) {
}
function handlePaid(order) {
window.localStorage.setItem(paywallKey, JSON.stringify(order));
window.localStorage.setItem(paymentKey, JSON.stringify(order));
if (typeof onPaid === "function") {
onPaid();
}
@ -35,7 +35,7 @@ export function FilePaywall(props) {
if (!order) {
return (
<div className="paywall">
<div className="payment">
<h3>
You must pay {FormatCurrency(pw.cost.amount, pw.cost.currency)} to view this file.
</h3>
@ -44,8 +44,8 @@ export function FilePaywall(props) {
);
} else {
switch (pw.service) {
case PaywallServices.Strike: {
return <LightningPaywall file={file} order={order} onReset={reset} onPaid={handlePaid}/>;
case PaymentServices.Strike: {
return <LightningPayment file={file} order={order} onReset={reset} onPaid={handlePaid}/>;
}
}
return null;

View File

@ -4,7 +4,7 @@ import {TextPreview} from "./TextPreview";
import FeatherIcon from "feather-icons-react";
import "./FilePreview.css";
import {FileEdit} from "./FileEdit";
import {FilePaywall} from "./FilePaywall";
import {FilePayment} from "./FilePayment";
import {useApi} from "./Api";
import {Helmet} from "react-helmet";
import {FormatBytes} from "./Util";
@ -27,9 +27,9 @@ export function FilePreview() {
}
function renderTypes() {
if (info.paywall && info.paywall.service !== 0) {
if (info.payment && info.payment.service !== 0) {
if (!order) {
return <FilePaywall file={info} onPaid={loadInfo}/>;
return <FilePayment file={info} onPaid={loadInfo}/>;
}
}
@ -132,7 +132,7 @@ export function FilePreview() {
useEffect(() => {
if (info) {
let fileLink = info.metadata?.url ?? `${ApiHost}/d/${info.id}`;
let order = window.localStorage.getItem(`paywall-${info.id}`);
let order = window.localStorage.getItem(`payment-${info.id}`);
if (order) {
let orderObj = JSON.parse(order);
setOrder(orderObj);

View File

@ -2,10 +2,10 @@
import {useEffect} from "react";
import {Countdown} from "./Countdown";
import {PaywallOrderState} from "./Const";
import {PaymentOrderState} from "./Const";
import {useApi} from "./Api";
export function LightningPaywall(props) {
export function LightningPayment(props) {
const {Api} = useApi();
const file = props.file;
const order = props.order;
@ -23,7 +23,7 @@ export function LightningPaywall(props) {
if (req.ok) {
let order = await req.json();
if (order.status === PaywallOrderState.Paid && typeof onPaid === "function") {
if (order.status === PaymentOrderState.Paid && typeof onPaid === "function") {
onPaid(order);
}
}

View File

@ -2,7 +2,7 @@
import {useState} from "react";
import {VoidButton} from "./VoidButton";
export function NoPaywallConfig(props) {
export function NoPaymentConfig(props) {
const [saveStatus, setSaveStatus] = useState();
const privateFile = props.privateFile;
const onSaveConfig = props.onSaveConfig;

View File

@ -1,18 +1,18 @@
import {useState} from "react";
import FeatherIcon from "feather-icons-react";
import {PaywallCurrencies} from "./Const";
import {PaymentCurrencies} from "./Const";
import {VoidButton} from "./VoidButton";
export function StrikePaywallConfig(props) {
export function StrikePaymentConfig(props) {
const file = props.file;
const privateFile = props.privateFile;
const onSaveConfig = props.onSaveConfig;
const paywall = file.paywall;
const payment = file.payment;
const editSecret = privateFile.metadata.editSecret;
const [username, setUsername] = useState(paywall?.handle ?? "hrf");
const [currency, setCurrency] = useState(paywall?.cost.currency ?? PaywallCurrencies.USD);
const [price, setPrice] = useState(paywall?.cost.amount ?? 1);
const [username, setUsername] = useState(payment?.handle ?? "hrf");
const [currency, setCurrency] = useState(payment?.cost.currency ?? PaymentCurrencies.USD);
const [price, setPrice] = useState(payment?.cost.amount ?? 1);
const [saveStatus, setSaveStatus] = useState();
async function saveStrikeConfig(e) {
@ -31,7 +31,7 @@ export function StrikePaywallConfig(props) {
if (await onSaveConfig(cfg)) {
setSaveStatus(true);
} else {
alert("Error settings paywall config!");
alert("Error settings payment config!");
setSaveStatus(false);
}
}
@ -45,10 +45,10 @@ export function StrikePaywallConfig(props) {
<dt>Currency:</dt>
<dd>
<select onChange={(e) => setCurrency(parseInt(e.target.value))} value={currency}>
<option value={PaywallCurrencies.BTC}>BTC</option>
<option value={PaywallCurrencies.USD}>USD</option>
<option value={PaywallCurrencies.EUR}>EUR</option>
<option value={PaywallCurrencies.GBP}>GBP</option>
<option value={PaymentCurrencies.BTC}>BTC</option>
<option value={PaymentCurrencies.USD}>USD</option>
<option value={PaymentCurrencies.EUR}>EUR</option>
<option value={PaymentCurrencies.GBP}>GBP</option>
</select>
</dd>
<dt>Price:</dt>

View File

@ -12,7 +12,7 @@ services:
redis:
image: "redis:alpine"
ports:
- "6379:6379"
- "6079:6379"
postgres:
image: "postgres:14.1"
ports:
@ -22,3 +22,5 @@ services:
- "POSTGRES_HOST_AUTH_METHOD=trust"
clamav:
image: "clamav/clamav"
ports:
- "3320:3310"