mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 14:04:26 +01:00
Greenfield: Refactor app endpoints (#6051)
* Greenfield: Refactor app endpoints - Do not change unset data - Clean up difference between request (template) and data (items/perks) - Add missing properties (form id and custom tip percentage) - Update docs * Revert ToSettings changes in GreenfieldAppsController
This commit is contained in:
@@ -9,41 +9,41 @@ namespace BTCPayServer.Client;
|
|||||||
public partial class BTCPayServerClient
|
public partial class BTCPayServerClient
|
||||||
{
|
{
|
||||||
public virtual async Task<PointOfSaleAppData> CreatePointOfSaleApp(string storeId,
|
public virtual async Task<PointOfSaleAppData> CreatePointOfSaleApp(string storeId,
|
||||||
CreatePointOfSaleAppRequest request, CancellationToken token = default)
|
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||||
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/stores/{storeId}/apps/pos", request, HttpMethod.Post, token);
|
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/stores/{storeId}/apps/pos", request, HttpMethod.Post, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<CrowdfundAppData> CreateCrowdfundApp(string storeId,
|
public virtual async Task<CrowdfundAppData> CreateCrowdfundApp(string storeId,
|
||||||
CreateCrowdfundAppRequest request, CancellationToken token = default)
|
CrowdfundAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||||
return await SendHttpRequest<CrowdfundAppData>($"api/v1/stores/{storeId}/apps/crowdfund", request, HttpMethod.Post, token);
|
return await SendHttpRequest<CrowdfundAppData>($"api/v1/stores/{storeId}/apps/crowdfund", request, HttpMethod.Post, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<PointOfSaleAppData> UpdatePointOfSaleApp(string appId,
|
public virtual async Task<PointOfSaleAppData> UpdatePointOfSaleApp(string appId,
|
||||||
CreatePointOfSaleAppRequest request, CancellationToken token = default)
|
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||||
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/apps/pos/{appId}", request, HttpMethod.Put, token);
|
return await SendHttpRequest<PointOfSaleAppData>($"api/v1/apps/pos/{appId}", request, HttpMethod.Put, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<AppDataBase> GetApp(string appId, CancellationToken token = default)
|
public virtual async Task<AppBaseData> GetApp(string appId, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||||
return await SendHttpRequest<AppDataBase>($"api/v1/apps/{appId}", null, HttpMethod.Get, token);
|
return await SendHttpRequest<AppBaseData>($"api/v1/apps/{appId}", null, HttpMethod.Get, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<AppDataBase[]> GetAllApps(string storeId, CancellationToken token = default)
|
public virtual async Task<AppBaseData[]> GetAllApps(string storeId, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (storeId == null) throw new ArgumentNullException(nameof(storeId));
|
if (storeId == null) throw new ArgumentNullException(nameof(storeId));
|
||||||
return await SendHttpRequest<AppDataBase[]>($"api/v1/stores/{storeId}/apps", null, HttpMethod.Get, token);
|
return await SendHttpRequest<AppBaseData[]>($"api/v1/stores/{storeId}/apps", null, HttpMethod.Get, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<AppDataBase[]> GetAllApps(CancellationToken token = default)
|
public virtual async Task<AppBaseData[]> GetAllApps(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return await SendHttpRequest<AppDataBase[]>("api/v1/apps", null, HttpMethod.Get, token);
|
return await SendHttpRequest<AppBaseData[]>("api/v1/apps", null, HttpMethod.Get, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<PointOfSaleAppData> GetPosApp(string appId, CancellationToken token = default)
|
public virtual async Task<PointOfSaleAppData> GetPosApp(string appId, CancellationToken token = default)
|
||||||
|
|||||||
21
BTCPayServer.Client/Models/AppBaseData.cs
Normal file
21
BTCPayServer.Client/Models/AppBaseData.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Client.Models;
|
||||||
|
|
||||||
|
public class AppBaseData
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string AppType { get; set; }
|
||||||
|
public string AppName { get; set; }
|
||||||
|
public string StoreId { get; set; }
|
||||||
|
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public bool? Archived { get; set; }
|
||||||
|
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||||
|
public DateTimeOffset Created { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAppRequest
|
||||||
|
{
|
||||||
|
public string AppName { get; set; }
|
||||||
|
}
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Converters;
|
|
||||||
|
|
||||||
namespace BTCPayServer.Client.Models
|
|
||||||
{
|
|
||||||
public enum PosViewType
|
|
||||||
{
|
|
||||||
Static,
|
|
||||||
Cart,
|
|
||||||
Light,
|
|
||||||
Print
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreateAppRequest
|
|
||||||
{
|
|
||||||
public string AppName { get; set; }
|
|
||||||
public string AppType { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreatePointOfSaleAppRequest : CreateAppRequest
|
|
||||||
{
|
|
||||||
public string Currency { get; set; } = null;
|
|
||||||
public string Title { get; set; } = null;
|
|
||||||
public string Description { get; set; } = null;
|
|
||||||
public string Template { get; set; } = null;
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public PosViewType DefaultView { get; set; }
|
|
||||||
public bool ShowItems { get; set; } = false;
|
|
||||||
public bool ShowCustomAmount { get; set; } = false;
|
|
||||||
public bool ShowDiscount { get; set; } = false;
|
|
||||||
public bool ShowSearch { get; set; } = true;
|
|
||||||
public bool ShowCategories { get; set; } = true;
|
|
||||||
public bool EnableTips { get; set; } = false;
|
|
||||||
public string CustomAmountPayButtonText { get; set; } = null;
|
|
||||||
public string FixedAmountPayButtonText { get; set; } = null;
|
|
||||||
public string TipText { get; set; } = null;
|
|
||||||
public string NotificationUrl { get; set; } = null;
|
|
||||||
public string RedirectUrl { get; set; } = null;
|
|
||||||
public bool? RedirectAutomatically { get; set; } = null;
|
|
||||||
public bool? Archived { get; set; } = null;
|
|
||||||
public string FormId { get; set; } = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CrowdfundResetEvery
|
|
||||||
{
|
|
||||||
Never,
|
|
||||||
Hour,
|
|
||||||
Day,
|
|
||||||
Month,
|
|
||||||
Year
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CreateCrowdfundAppRequest : CreateAppRequest
|
|
||||||
{
|
|
||||||
public string Title { get; set; } = null;
|
|
||||||
public bool? Enabled { get; set; } = null;
|
|
||||||
public bool? EnforceTargetAmount { get; set; } = null;
|
|
||||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
|
||||||
public DateTimeOffset? StartDate { get; set; } = null;
|
|
||||||
public string TargetCurrency { get; set; } = null;
|
|
||||||
public string Description { get; set; } = null;
|
|
||||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
|
||||||
public DateTimeOffset? EndDate { get; set; } = null;
|
|
||||||
public decimal? TargetAmount { get; set; } = null;
|
|
||||||
public string MainImageUrl { get; set; } = null;
|
|
||||||
public string NotificationUrl { get; set; } = null;
|
|
||||||
public string Tagline { get; set; } = null;
|
|
||||||
public string PerksTemplate { get; set; } = null;
|
|
||||||
public bool? SoundsEnabled { get; set; } = null;
|
|
||||||
public string DisqusShortname { get; set; } = null;
|
|
||||||
public bool? AnimationsEnabled { get; set; } = null;
|
|
||||||
public int? ResetEveryAmount { get; set; } = null;
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public CrowdfundResetEvery ResetEvery { get; set; } = CrowdfundResetEvery.Never;
|
|
||||||
public bool? DisplayPerksValue { get; set; } = null;
|
|
||||||
public bool? DisplayPerksRanking { get; set; } = null;
|
|
||||||
public bool? SortPerksByPopularity { get; set; } = null;
|
|
||||||
public bool? Archived { get; set; } = null;
|
|
||||||
public string[] Sounds { get; set; } = null;
|
|
||||||
public string[] AnimationColors { get; set; } = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
55
BTCPayServer.Client/Models/CrowdfundAppData.cs
Normal file
55
BTCPayServer.Client/Models/CrowdfundAppData.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Client.Models;
|
||||||
|
|
||||||
|
public abstract class CrowdfundBaseData : AppBaseData
|
||||||
|
{
|
||||||
|
public string? Title { get; set; }
|
||||||
|
public bool? Enabled { get; set; }
|
||||||
|
public bool? EnforceTargetAmount { get; set; }
|
||||||
|
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||||
|
public DateTimeOffset? StartDate { get; set; }
|
||||||
|
public string? TargetCurrency { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||||
|
public DateTimeOffset? EndDate { get; set; }
|
||||||
|
public decimal? TargetAmount { get; set; }
|
||||||
|
public string? MainImageUrl { get; set; }
|
||||||
|
public string? NotificationUrl { get; set; }
|
||||||
|
public string? Tagline { get; set; }
|
||||||
|
public bool? DisqusEnabled { get; set; }
|
||||||
|
public string? DisqusShortname { get; set; }
|
||||||
|
public bool? SoundsEnabled { get; set; }
|
||||||
|
public bool? AnimationsEnabled { get; set; }
|
||||||
|
public int? ResetEveryAmount { get; set; }
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public CrowdfundResetEvery? ResetEvery { get; set; }
|
||||||
|
public bool? DisplayPerksValue { get; set; }
|
||||||
|
public bool? DisplayPerksRanking { get; set; }
|
||||||
|
public bool? SortPerksByPopularity { get; set; }
|
||||||
|
public string[]? Sounds { get; set; }
|
||||||
|
public string[]? AnimationColors { get; set; }
|
||||||
|
public string? FormId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CrowdfundAppData : CrowdfundBaseData
|
||||||
|
{
|
||||||
|
public object? Perks { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CrowdfundAppRequest : CrowdfundBaseData, IAppRequest
|
||||||
|
{
|
||||||
|
public string? PerksTemplate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CrowdfundResetEvery
|
||||||
|
{
|
||||||
|
Never,
|
||||||
|
Hour,
|
||||||
|
Day,
|
||||||
|
Month,
|
||||||
|
Year
|
||||||
|
}
|
||||||
@@ -1,67 +1,46 @@
|
|||||||
using System;
|
#nullable enable
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
namespace BTCPayServer.Client.Models
|
namespace BTCPayServer.Client.Models;
|
||||||
{
|
|
||||||
public class AppDataBase
|
|
||||||
{
|
|
||||||
public string Id { get; set; }
|
|
||||||
public string AppType { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string StoreId { get; set; }
|
|
||||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public bool? Archived { get; set; }
|
|
||||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
|
||||||
public DateTimeOffset Created { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PointOfSaleAppData : AppDataBase
|
public abstract class PointOfSaleBaseData : AppBaseData
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public string DefaultView { get; set; }
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
public bool ShowItems { get; set; }
|
public PosViewType? DefaultView { get; set; }
|
||||||
public bool ShowCustomAmount { get; set; }
|
public bool? ShowItems { get; set; }
|
||||||
public bool ShowDiscount { get; set; }
|
public bool? ShowCustomAmount { get; set; }
|
||||||
public bool ShowSearch { get; set; }
|
public bool? ShowDiscount { get; set; }
|
||||||
public bool ShowCategories { get; set; }
|
public bool? ShowSearch { get; set; }
|
||||||
public bool EnableTips { get; set; }
|
public bool? ShowCategories { get; set; }
|
||||||
public string Currency { get; set; }
|
public bool? EnableTips { get; set; }
|
||||||
public object Items { get; set; }
|
public string? Currency { get; set; }
|
||||||
public string FixedAmountPayButtonText { get; set; }
|
public string? FixedAmountPayButtonText { get; set; }
|
||||||
public string CustomAmountPayButtonText { get; set; }
|
public string? CustomAmountPayButtonText { get; set; }
|
||||||
public string TipText { get; set; }
|
public string? TipText { get; set; }
|
||||||
public string NotificationUrl { get; set; }
|
public string? NotificationUrl { get; set; }
|
||||||
public string RedirectUrl { get; set; }
|
public string? RedirectUrl { get; set; }
|
||||||
public string Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public bool? RedirectAutomatically { get; set; }
|
public bool? RedirectAutomatically { get; set; }
|
||||||
|
public int[]? CustomTipPercentages { get; set; }
|
||||||
|
public string? FormId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CrowdfundAppData : AppDataBase
|
public class PointOfSaleAppData : PointOfSaleBaseData
|
||||||
{
|
{
|
||||||
public string Title { get; set; }
|
public object? Items { get; set; }
|
||||||
public bool Enabled { get; set; }
|
|
||||||
public bool EnforceTargetAmount { get; set; }
|
|
||||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
|
||||||
public DateTimeOffset? StartDate { get; set; }
|
|
||||||
public string TargetCurrency { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
|
||||||
public DateTimeOffset? EndDate { get; set; }
|
|
||||||
public decimal? TargetAmount { get; set; }
|
|
||||||
public string MainImageUrl { get; set; }
|
|
||||||
public string NotificationUrl { get; set; }
|
|
||||||
public string Tagline { get; set; }
|
|
||||||
public object Perks { get; set; }
|
|
||||||
public bool DisqusEnabled { get; set; }
|
|
||||||
public string DisqusShortname { get; set; }
|
|
||||||
public bool SoundsEnabled { get; set; }
|
|
||||||
public bool AnimationsEnabled { get; set; }
|
|
||||||
public int ResetEveryAmount { get; set; }
|
|
||||||
public string ResetEvery { get; set; }
|
|
||||||
public bool DisplayPerksValue { get; set; }
|
|
||||||
public bool DisplayPerksRanking { get; set; }
|
|
||||||
public bool SortPerksByPopularity { get; set; }
|
|
||||||
public string[] Sounds { get; set; }
|
|
||||||
public string[] AnimationColors { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PointOfSaleAppRequest : PointOfSaleBaseData, IAppRequest
|
||||||
|
{
|
||||||
|
public string? Template { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PosViewType
|
||||||
|
{
|
||||||
|
Static,
|
||||||
|
Cart,
|
||||||
|
Light,
|
||||||
|
Print
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,11 +253,11 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Test validation for creating the app
|
// Test validation for creating the app
|
||||||
await AssertValidationError(new[] { "AppName" },
|
await AssertValidationError(new[] { "AppName" },
|
||||||
async () => await client.CreatePointOfSaleApp(user.StoreId, new CreatePointOfSaleAppRequest() { }));
|
async () => await client.CreatePointOfSaleApp(user.StoreId, new PointOfSaleAppRequest()));
|
||||||
await AssertValidationError(new[] { "AppName" },
|
await AssertValidationError(new[] { "AppName" },
|
||||||
async () => await client.CreatePointOfSaleApp(
|
async () => await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "this is a really long app name this is a really long app name this is a really long app name",
|
AppName = "this is a really long app name this is a really long app name this is a really long app name",
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "Currency" },
|
await AssertValidationError(new[] { "Currency" },
|
||||||
async () => await client.CreatePointOfSaleApp(
|
async () => await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
Currency = "fake currency"
|
Currency = "fake currency"
|
||||||
@@ -276,7 +276,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "Template" },
|
await AssertValidationError(new[] { "Template" },
|
||||||
async () => await client.CreatePointOfSaleApp(
|
async () => await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
Template = "lol invalid template"
|
Template = "lol invalid template"
|
||||||
@@ -286,7 +286,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "AppName", "Currency", "Template" },
|
await AssertValidationError(new[] { "AppName", "Currency", "Template" },
|
||||||
async () => await client.CreatePointOfSaleApp(
|
async () => await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
Currency = "fake currency",
|
Currency = "fake currency",
|
||||||
Template = "lol invalid template"
|
Template = "lol invalid template"
|
||||||
@@ -297,14 +297,14 @@ namespace BTCPayServer.Tests
|
|||||||
// Test creating a POS app successfully
|
// Test creating a POS app successfully
|
||||||
var app = await client.CreatePointOfSaleApp(
|
var app = await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "test app from API",
|
AppName = "test app from API",
|
||||||
Currency = "JPY",
|
Currency = "JPY",
|
||||||
Title = "test app title"
|
Title = "test app title"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Assert.Equal("test app from API", app.Name);
|
Assert.Equal("test app from API", app.AppName);
|
||||||
Assert.Equal(user.StoreId, app.StoreId);
|
Assert.Equal(user.StoreId, app.StoreId);
|
||||||
Assert.Equal("PointOfSale", app.AppType);
|
Assert.Equal("PointOfSale", app.AppType);
|
||||||
Assert.Equal("test app title", app.Title);
|
Assert.Equal("test app title", app.Title);
|
||||||
@@ -313,12 +313,19 @@ namespace BTCPayServer.Tests
|
|||||||
// Test title falls back to name
|
// Test title falls back to name
|
||||||
app = await client.CreatePointOfSaleApp(
|
app = await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "test app name"
|
AppName = "test app name",
|
||||||
|
Description = "test description",
|
||||||
|
ShowItems = true,
|
||||||
|
ShowCategories = false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Assert.Equal("test app name", app.Title);
|
Assert.Equal("test app name", app.Title);
|
||||||
|
Assert.Equal("test description", app.Description);
|
||||||
|
Assert.True(app.ShowItems);
|
||||||
|
Assert.False(app.ShowCategories);
|
||||||
|
Assert.False(app.ShowDiscount);
|
||||||
|
|
||||||
// Make sure we return a 404 if we try to get an app that doesn't exist
|
// Make sure we return a 404 if we try to get an app that doesn't exist
|
||||||
await AssertHttpError(404, async () =>
|
await AssertHttpError(404, async () =>
|
||||||
@@ -332,30 +339,33 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Test that we can retrieve the app data
|
// Test that we can retrieve the app data
|
||||||
var retrievedApp = await client.GetApp(app.Id);
|
var retrievedApp = await client.GetApp(app.Id);
|
||||||
Assert.Equal(app.Name, retrievedApp.Name);
|
Assert.Equal(app.AppName, retrievedApp.AppName);
|
||||||
Assert.Equal(app.StoreId, retrievedApp.StoreId);
|
Assert.Equal(app.StoreId, retrievedApp.StoreId);
|
||||||
Assert.Equal(app.AppType, retrievedApp.AppType);
|
Assert.Equal(app.AppType, retrievedApp.AppType);
|
||||||
|
|
||||||
// Test that we can update the app data
|
// Test that we can update the app data
|
||||||
await client.UpdatePointOfSaleApp(
|
var retrievedPosApp = await client.UpdatePointOfSaleApp(
|
||||||
app.Id,
|
app.Id,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "new app name",
|
AppName = "new app name",
|
||||||
Title = "new app title",
|
Title = "new app title",
|
||||||
Archived = true
|
Archived = true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Assert.Equal("new app name", retrievedPosApp.AppName);
|
||||||
|
Assert.Equal("new app title", retrievedPosApp.Title);
|
||||||
|
Assert.True(retrievedPosApp.Archived);
|
||||||
|
|
||||||
// Test generic GET app endpoint first
|
// Test generic GET app endpoint first
|
||||||
retrievedApp = await client.GetApp(app.Id);
|
retrievedApp = await client.GetApp(app.Id);
|
||||||
Assert.Equal("new app name", retrievedApp.Name);
|
Assert.Equal("new app name", retrievedApp.AppName);
|
||||||
Assert.True(retrievedApp.Archived);
|
Assert.True(retrievedApp.Archived);
|
||||||
|
|
||||||
// Test the POS-specific endpoint also
|
// Test the POS-specific endpoint also
|
||||||
var retrievedPosApp = await client.GetPosApp(app.Id);
|
retrievedPosApp = await client.GetPosApp(app.Id);
|
||||||
Assert.Equal("new app name", retrievedPosApp.Name);
|
Assert.Equal("new app name", retrievedPosApp.AppName);
|
||||||
Assert.Equal("new app title", retrievedPosApp.Title);
|
Assert.Equal("new app title", retrievedPosApp.Title);
|
||||||
Assert.True(retrievedPosApp.Archived);
|
|
||||||
|
|
||||||
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
||||||
await AssertHttpError(404, async () =>
|
await AssertHttpError(404, async () =>
|
||||||
@@ -383,11 +393,11 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Test validation for creating the app
|
// Test validation for creating the app
|
||||||
await AssertValidationError(new[] { "AppName" },
|
await AssertValidationError(new[] { "AppName" },
|
||||||
async () => await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() { }));
|
async () => await client.CreateCrowdfundApp(user.StoreId, new CrowdfundAppRequest()));
|
||||||
await AssertValidationError(new[] { "AppName" },
|
await AssertValidationError(new[] { "AppName" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "this is a really long app name this is a really long app name this is a really long app name",
|
AppName = "this is a really long app name this is a really long app name this is a really long app name",
|
||||||
}
|
}
|
||||||
@@ -396,7 +406,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "TargetCurrency" },
|
await AssertValidationError(new[] { "TargetCurrency" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
TargetCurrency = "fake currency"
|
TargetCurrency = "fake currency"
|
||||||
@@ -406,7 +416,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "PerksTemplate" },
|
await AssertValidationError(new[] { "PerksTemplate" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
PerksTemplate = "lol invalid template"
|
PerksTemplate = "lol invalid template"
|
||||||
@@ -416,7 +426,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "AppName", "TargetCurrency", "PerksTemplate" },
|
await AssertValidationError(new[] { "AppName", "TargetCurrency", "PerksTemplate" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
TargetCurrency = "fake currency",
|
TargetCurrency = "fake currency",
|
||||||
PerksTemplate = "lol invalid template"
|
PerksTemplate = "lol invalid template"
|
||||||
@@ -426,7 +436,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "AnimationColors" },
|
await AssertValidationError(new[] { "AnimationColors" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
AnimationColors = new string[] { }
|
AnimationColors = new string[] { }
|
||||||
@@ -436,7 +446,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "AnimationColors" },
|
await AssertValidationError(new[] { "AnimationColors" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
AnimationColors = new string[] { " ", " " }
|
AnimationColors = new string[] { " ", " " }
|
||||||
@@ -446,7 +456,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "Sounds" },
|
await AssertValidationError(new[] { "Sounds" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
Sounds = new string[] { " " }
|
Sounds = new string[] { " " }
|
||||||
@@ -456,7 +466,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "Sounds" },
|
await AssertValidationError(new[] { "Sounds" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
Sounds = new string[] { " ", " ", " " }
|
Sounds = new string[] { " ", " ", " " }
|
||||||
@@ -466,7 +476,7 @@ namespace BTCPayServer.Tests
|
|||||||
await AssertValidationError(new[] { "EndDate" },
|
await AssertValidationError(new[] { "EndDate" },
|
||||||
async () => await client.CreateCrowdfundApp(
|
async () => await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "good name",
|
AppName = "good name",
|
||||||
StartDate = DateTime.Parse("1998-01-01"),
|
StartDate = DateTime.Parse("1998-01-01"),
|
||||||
@@ -478,13 +488,13 @@ namespace BTCPayServer.Tests
|
|||||||
// Test creating a crowdfund app
|
// Test creating a crowdfund app
|
||||||
var app = await client.CreateCrowdfundApp(
|
var app = await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest()
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "test app from API",
|
AppName = "test app from API",
|
||||||
Title = "test app title"
|
Title = "test app title"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Assert.Equal("test app from API", app.Name);
|
Assert.Equal("test app from API", app.AppName);
|
||||||
Assert.Equal(user.StoreId, app.StoreId);
|
Assert.Equal(user.StoreId, app.StoreId);
|
||||||
Assert.Equal("Crowdfund", app.AppType);
|
Assert.Equal("Crowdfund", app.AppType);
|
||||||
Assert.False(app.Archived);
|
Assert.False(app.Archived);
|
||||||
@@ -492,9 +502,10 @@ namespace BTCPayServer.Tests
|
|||||||
// Test title falls back to name
|
// Test title falls back to name
|
||||||
app = await client.CreateCrowdfundApp(
|
app = await client.CreateCrowdfundApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreateCrowdfundAppRequest
|
new CrowdfundAppRequest
|
||||||
{
|
{
|
||||||
AppName = "test app name"
|
AppName = "test app name",
|
||||||
|
Description = "test description"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Assert.Equal("test app name", app.Title);
|
Assert.Equal("test app name", app.Title);
|
||||||
@@ -511,15 +522,16 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
// Test that we can retrieve the app data
|
// Test that we can retrieve the app data
|
||||||
var retrievedApp = await client.GetApp(app.Id);
|
var retrievedApp = await client.GetApp(app.Id);
|
||||||
Assert.Equal(app.Name, retrievedApp.Name);
|
Assert.Equal(app.AppName, retrievedApp.AppName);
|
||||||
Assert.Equal(app.StoreId, retrievedApp.StoreId);
|
Assert.Equal(app.StoreId, retrievedApp.StoreId);
|
||||||
Assert.Equal(app.AppType, retrievedApp.AppType);
|
Assert.Equal(app.AppType, retrievedApp.AppType);
|
||||||
Assert.False(retrievedApp.Archived);
|
Assert.False(retrievedApp.Archived);
|
||||||
|
|
||||||
// Test the crowdfund-specific endpoint also
|
// Test the crowdfund-specific endpoint also
|
||||||
var retrievedCfApp = await client.GetCrowdfundApp(app.Id);
|
var retrievedCfApp = await client.GetCrowdfundApp(app.Id);
|
||||||
Assert.Equal(app.Name, retrievedCfApp.Name);
|
Assert.Equal(app.AppName, retrievedCfApp.AppName);
|
||||||
Assert.Equal(app.Title, retrievedCfApp.Title);
|
Assert.Equal(app.Title, retrievedCfApp.Title);
|
||||||
|
Assert.Equal("test description", retrievedCfApp.Description);
|
||||||
Assert.False(retrievedCfApp.Archived);
|
Assert.False(retrievedCfApp.Archived);
|
||||||
|
|
||||||
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
// Make sure we return a 404 if we try to delete an app that doesn't exist
|
||||||
@@ -548,17 +560,17 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
var posApp = await client.CreatePointOfSaleApp(
|
var posApp = await client.CreatePointOfSaleApp(
|
||||||
user.StoreId,
|
user.StoreId,
|
||||||
new CreatePointOfSaleAppRequest()
|
new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "test app from API",
|
AppName = "test app from API",
|
||||||
Currency = "JPY"
|
Currency = "JPY"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
var crowdfundApp = await client.CreateCrowdfundApp(user.StoreId, new CreateCrowdfundAppRequest() { AppName = "test app from API" });
|
var crowdfundApp = await client.CreateCrowdfundApp(user.StoreId, new CrowdfundAppRequest { AppName = "test app from API" });
|
||||||
|
|
||||||
// Create another store and one app on it so we can get all apps from all stores for the user below
|
// Create another store and one app on it so we can get all apps from all stores for the user below
|
||||||
var newStore = await client.CreateStore(new CreateStoreRequest() { Name = "A" });
|
var newStore = await client.CreateStore(new CreateStoreRequest { Name = "A" });
|
||||||
var newApp = await client.CreateCrowdfundApp(newStore.Id, new CreateCrowdfundAppRequest() { AppName = "new app" });
|
var newApp = await client.CreateCrowdfundApp(newStore.Id, new CrowdfundAppRequest { AppName = "new app" });
|
||||||
|
|
||||||
Assert.NotEqual(newApp.Id, user.StoreId);
|
Assert.NotEqual(newApp.Id, user.StoreId);
|
||||||
|
|
||||||
@@ -567,12 +579,12 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
Assert.Equal(2, apps.Length);
|
Assert.Equal(2, apps.Length);
|
||||||
|
|
||||||
Assert.Equal(posApp.Name, apps[0].Name);
|
Assert.Equal(posApp.AppName, apps[0].AppName);
|
||||||
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
||||||
Assert.Equal(posApp.AppType, apps[0].AppType);
|
Assert.Equal(posApp.AppType, apps[0].AppType);
|
||||||
Assert.False(apps[0].Archived);
|
Assert.False(apps[0].Archived);
|
||||||
|
|
||||||
Assert.Equal(crowdfundApp.Name, apps[1].Name);
|
Assert.Equal(crowdfundApp.AppName, apps[1].AppName);
|
||||||
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
||||||
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
||||||
Assert.False(apps[1].Archived);
|
Assert.False(apps[1].Archived);
|
||||||
@@ -582,17 +594,17 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
Assert.Equal(3, apps.Length);
|
Assert.Equal(3, apps.Length);
|
||||||
|
|
||||||
Assert.Equal(posApp.Name, apps[0].Name);
|
Assert.Equal(posApp.AppName, apps[0].AppName);
|
||||||
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
Assert.Equal(posApp.StoreId, apps[0].StoreId);
|
||||||
Assert.Equal(posApp.AppType, apps[0].AppType);
|
Assert.Equal(posApp.AppType, apps[0].AppType);
|
||||||
Assert.False(apps[0].Archived);
|
Assert.False(apps[0].Archived);
|
||||||
|
|
||||||
Assert.Equal(crowdfundApp.Name, apps[1].Name);
|
Assert.Equal(crowdfundApp.AppName, apps[1].AppName);
|
||||||
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
Assert.Equal(crowdfundApp.StoreId, apps[1].StoreId);
|
||||||
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
Assert.Equal(crowdfundApp.AppType, apps[1].AppType);
|
||||||
Assert.False(apps[1].Archived);
|
Assert.False(apps[1].Archived);
|
||||||
|
|
||||||
Assert.Equal(newApp.Name, apps[2].Name);
|
Assert.Equal(newApp.AppName, apps[2].AppName);
|
||||||
Assert.Equal(newApp.StoreId, apps[2].StoreId);
|
Assert.Equal(newApp.StoreId, apps[2].StoreId);
|
||||||
Assert.Equal(newApp.AppType, apps[2].AppType);
|
Assert.Equal(newApp.AppType, apps[2].AppType);
|
||||||
Assert.False(apps[2].Archived);
|
Assert.False(apps[2].Archived);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ using MarkPayoutRequest = BTCPayServer.Client.Models.MarkPayoutRequest;
|
|||||||
using PaymentRequestData = BTCPayServer.Client.Models.PaymentRequestData;
|
using PaymentRequestData = BTCPayServer.Client.Models.PaymentRequestData;
|
||||||
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using PosViewType = BTCPayServer.Client.Models.PosViewType;
|
||||||
|
|
||||||
namespace BTCPayServer.Tests
|
namespace BTCPayServer.Tests
|
||||||
{
|
{
|
||||||
@@ -3109,20 +3110,20 @@ namespace BTCPayServer.Tests
|
|||||||
var client = await acc.CreateClient();
|
var client = await acc.CreateClient();
|
||||||
var posController = acc.GetController<UIPointOfSaleController>();
|
var posController = acc.GetController<UIPointOfSaleController>();
|
||||||
|
|
||||||
var app = await client.CreatePointOfSaleApp(acc.StoreId, new CreatePointOfSaleAppRequest()
|
var app = await client.CreatePointOfSaleApp(acc.StoreId, new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "Static",
|
AppName = "Static",
|
||||||
DefaultView = Client.Models.PosViewType.Static,
|
DefaultView = PosViewType.Static,
|
||||||
Template = new PointOfSaleSettings().Template
|
Template = new PointOfSaleSettings().Template
|
||||||
});
|
});
|
||||||
var resp = await posController.ViewPointOfSale(app.Id, choiceKey: "green-tea");
|
var resp = await posController.ViewPointOfSale(app.Id, choiceKey: "green-tea");
|
||||||
var invoiceId = GetInvoiceId(resp);
|
var invoiceId = GetInvoiceId(resp);
|
||||||
await acc.PayOnChain(invoiceId);
|
await acc.PayOnChain(invoiceId);
|
||||||
|
|
||||||
app = await client.CreatePointOfSaleApp(acc.StoreId, new CreatePointOfSaleAppRequest()
|
app = await client.CreatePointOfSaleApp(acc.StoreId, new PointOfSaleAppRequest
|
||||||
{
|
{
|
||||||
AppName = "Cart",
|
AppName = "Cart",
|
||||||
DefaultView = Client.Models.PosViewType.Cart,
|
DefaultView = PosViewType.Cart,
|
||||||
Template = new PointOfSaleSettings().Template
|
Template = new PointOfSaleSettings().Template
|
||||||
});
|
});
|
||||||
resp = await posController.ViewPointOfSale(app.Id, posData: new JObject()
|
resp = await posController.ViewPointOfSale(app.Id, posData: new JObject()
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ using Microsoft.AspNetCore.Cors;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PosViewType = BTCPayServer.Plugins.PointOfSale.PosViewType;
|
using CrowdfundResetEvery = BTCPayServer.Client.Models.CrowdfundResetEvery;
|
||||||
|
using PosViewType = BTCPayServer.Client.Models.PosViewType;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers.Greenfield
|
namespace BTCPayServer.Controllers.Greenfield
|
||||||
{
|
{
|
||||||
@@ -47,19 +48,20 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
[HttpPost("~/api/v1/stores/{storeId}/apps/crowdfund")]
|
[HttpPost("~/api/v1/stores/{storeId}/apps/crowdfund")]
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
public async Task<IActionResult> CreateCrowdfundApp(string storeId, CreateCrowdfundAppRequest request)
|
public async Task<IActionResult> CreateCrowdfundApp(string storeId, CrowdfundAppRequest request)
|
||||||
{
|
{
|
||||||
var store = await _storeRepository.FindStore(storeId);
|
var store = await _storeRepository.FindStore(storeId);
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return this.CreateAPIError(404, "store-not-found", "The store was not found");
|
return this.CreateAPIError(404, "store-not-found", "The store was not found");
|
||||||
|
|
||||||
// This is not obvious but we must have a non-null currency or else request validation may work incorrectly
|
// This is not obvious, but we must have a non-null currency or else request validation may not work correctly
|
||||||
request.TargetCurrency = request.TargetCurrency ?? store.GetStoreBlob().DefaultCurrency;
|
request.TargetCurrency ??= store.GetStoreBlob().DefaultCurrency;
|
||||||
|
|
||||||
var validationResult = ValidateCrowdfundAppRequest(request);
|
ValidateAppRequest(request);
|
||||||
if (validationResult != null)
|
ValidateCrowdfundAppRequest(request);
|
||||||
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return validationResult;
|
return this.CreateValidationError(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
var appData = new AppData
|
var appData = new AppData
|
||||||
@@ -70,7 +72,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
Archived = request.Archived ?? false
|
Archived = request.Archived ?? false
|
||||||
};
|
};
|
||||||
|
|
||||||
appData.SetSettings(ToCrowdfundSettings(request));
|
var settings = ToCrowdfundSettings(request, new CrowdfundSettings { Title = request.Title ?? request.AppName });
|
||||||
|
appData.SetSettings(settings);
|
||||||
|
|
||||||
await _appService.UpdateOrCreateApp(appData);
|
await _appService.UpdateOrCreateApp(appData);
|
||||||
|
|
||||||
@@ -79,19 +82,20 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
[HttpPost("~/api/v1/stores/{storeId}/apps/pos")]
|
[HttpPost("~/api/v1/stores/{storeId}/apps/pos")]
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
public async Task<IActionResult> CreatePointOfSaleApp(string storeId, CreatePointOfSaleAppRequest request)
|
public async Task<IActionResult> CreatePointOfSaleApp(string storeId, PointOfSaleAppRequest request)
|
||||||
{
|
{
|
||||||
var store = await _storeRepository.FindStore(storeId);
|
var store = await _storeRepository.FindStore(storeId);
|
||||||
if (store == null)
|
if (store == null)
|
||||||
return this.CreateAPIError(404, "store-not-found", "The store was not found");
|
return this.CreateAPIError(404, "store-not-found", "The store was not found");
|
||||||
|
|
||||||
// This is not obvious but we must have a non-null currency or else request validation may work incorrectly
|
// This is not obvious, but we must have a non-null currency or else request validation may not work correctly
|
||||||
request.Currency = request.Currency ?? store.GetStoreBlob().DefaultCurrency;
|
request.Currency ??= store.GetStoreBlob().DefaultCurrency;
|
||||||
|
|
||||||
var validationResult = ValidatePOSAppRequest(request);
|
ValidateAppRequest(request);
|
||||||
if (validationResult != null)
|
ValidatePOSAppRequest(request);
|
||||||
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return validationResult;
|
return this.CreateValidationError(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
var appData = new AppData
|
var appData = new AppData
|
||||||
@@ -102,7 +106,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
Archived = request.Archived ?? false
|
Archived = request.Archived ?? false
|
||||||
};
|
};
|
||||||
|
|
||||||
appData.SetSettings(ToPointOfSaleSettings(request));
|
var settings = ToPointOfSaleSettings(request, new PointOfSaleSettings { Title = request.Title ?? request.AppName });
|
||||||
|
appData.SetSettings(settings);
|
||||||
|
|
||||||
await _appService.UpdateOrCreateApp(appData);
|
await _appService.UpdateOrCreateApp(appData);
|
||||||
|
|
||||||
@@ -111,7 +116,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
[HttpPut("~/api/v1/apps/pos/{appId}")]
|
[HttpPut("~/api/v1/apps/pos/{appId}")]
|
||||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
public async Task<IActionResult> UpdatePointOfSaleApp(string appId, CreatePointOfSaleAppRequest request)
|
public async Task<IActionResult> UpdatePointOfSaleApp(string appId, PointOfSaleAppRequest request)
|
||||||
{
|
{
|
||||||
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType, includeArchived: true);
|
var app = await _appService.GetApp(appId, PointOfSaleAppType.AppType, includeArchived: true);
|
||||||
if (app == null)
|
if (app == null)
|
||||||
@@ -121,21 +126,28 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
var settings = app.GetSettings<PointOfSaleSettings>();
|
var settings = app.GetSettings<PointOfSaleSettings>();
|
||||||
|
|
||||||
// This is not obvious but we must have a non-null currency or else request validation may work incorrectly
|
// This is not obvious, but we must have a non-null currency or else request validation may not work correctly
|
||||||
request.Currency = request.Currency ?? settings.Currency;
|
request.Currency ??= settings.Currency;
|
||||||
|
|
||||||
var validationResult = ValidatePOSAppRequest(request);
|
ValidatePOSAppRequest(request);
|
||||||
if (validationResult != null)
|
if (!string.IsNullOrEmpty(request.AppName))
|
||||||
{
|
{
|
||||||
return validationResult;
|
ValidateAppRequest(request);
|
||||||
|
}
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return this.CreateValidationError(ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(request.AppName))
|
||||||
|
{
|
||||||
app.Name = request.AppName;
|
app.Name = request.AppName;
|
||||||
|
}
|
||||||
if (request.Archived != null)
|
if (request.Archived != null)
|
||||||
{
|
{
|
||||||
app.Archived = request.Archived.Value;
|
app.Archived = request.Archived.Value;
|
||||||
}
|
}
|
||||||
app.SetSettings(ToPointOfSaleSettings(request));
|
app.SetSettings(ToPointOfSaleSettings(request, settings));
|
||||||
|
|
||||||
await _appService.UpdateOrCreateApp(app);
|
await _appService.UpdateOrCreateApp(app);
|
||||||
|
|
||||||
@@ -218,10 +230,11 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
return this.CreateAPIError(404, "app-not-found", "The app with specified ID was not found");
|
return this.CreateAPIError(404, "app-not-found", "The app with specified ID was not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
private CrowdfundSettings ToCrowdfundSettings(CreateCrowdfundAppRequest request)
|
private CrowdfundSettings ToCrowdfundSettings(CrowdfundAppRequest request, CrowdfundSettings settings)
|
||||||
{
|
{
|
||||||
var parsedSounds = ValidateStringArray(request.Sounds);
|
var parsedSounds = ValidateStringArray(request.Sounds);
|
||||||
var parsedColors = ValidateStringArray(request.AnimationColors);
|
var parsedColors = ValidateStringArray(request.AnimationColors);
|
||||||
|
Enum.TryParse<BTCPayServer.Services.Apps.CrowdfundResetEvery>(request.ResetEvery.ToString(), true, out var resetEvery);
|
||||||
|
|
||||||
return new CrowdfundSettings
|
return new CrowdfundSettings
|
||||||
{
|
{
|
||||||
@@ -244,32 +257,36 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
SoundsEnabled = request.SoundsEnabled ?? parsedSounds != null,
|
SoundsEnabled = request.SoundsEnabled ?? parsedSounds != null,
|
||||||
AnimationsEnabled = request.AnimationsEnabled ?? parsedColors != null,
|
AnimationsEnabled = request.AnimationsEnabled ?? parsedColors != null,
|
||||||
ResetEveryAmount = request.ResetEveryAmount ?? 1,
|
ResetEveryAmount = request.ResetEveryAmount ?? 1,
|
||||||
ResetEvery = (Services.Apps.CrowdfundResetEvery)request.ResetEvery,
|
ResetEvery = resetEvery,
|
||||||
DisplayPerksValue = request.DisplayPerksValue ?? false,
|
DisplayPerksValue = request.DisplayPerksValue ?? false,
|
||||||
DisplayPerksRanking = request.DisplayPerksRanking ?? false,
|
DisplayPerksRanking = request.DisplayPerksRanking ?? false,
|
||||||
SortPerksByPopularity = request.SortPerksByPopularity ?? false,
|
SortPerksByPopularity = request.SortPerksByPopularity ?? false,
|
||||||
Sounds = parsedSounds ?? new CrowdfundSettings().Sounds,
|
Sounds = parsedSounds ?? new CrowdfundSettings().Sounds,
|
||||||
AnimationColors = parsedColors ?? new CrowdfundSettings().AnimationColors
|
AnimationColors = parsedColors ?? new CrowdfundSettings().AnimationColors,
|
||||||
|
FormId = request.FormId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private PointOfSaleSettings ToPointOfSaleSettings(CreatePointOfSaleAppRequest request)
|
private PointOfSaleSettings ToPointOfSaleSettings(PointOfSaleAppRequest request, PointOfSaleSettings settings)
|
||||||
{
|
{
|
||||||
|
Enum.TryParse<BTCPayServer.Plugins.PointOfSale.PosViewType>(request.DefaultView.ToString(), true, out var defaultView);
|
||||||
|
|
||||||
return new PointOfSaleSettings
|
return new PointOfSaleSettings
|
||||||
{
|
{
|
||||||
Title = request.Title ?? request.AppName,
|
Title = request.Title ?? request.AppName,
|
||||||
DefaultView = (PosViewType)request.DefaultView,
|
DefaultView = defaultView,
|
||||||
ShowItems = request.ShowItems,
|
ShowItems = request.ShowItems ?? false,
|
||||||
ShowCustomAmount = request.ShowCustomAmount,
|
ShowCustomAmount = request.ShowCustomAmount ?? false,
|
||||||
ShowDiscount = request.ShowDiscount,
|
ShowDiscount = request.ShowDiscount ?? false,
|
||||||
ShowSearch = request.ShowSearch,
|
ShowSearch = request.ShowSearch ?? false,
|
||||||
ShowCategories = request.ShowCategories,
|
ShowCategories = request.ShowCategories ?? false,
|
||||||
EnableTips = request.EnableTips,
|
EnableTips = request.EnableTips ?? false,
|
||||||
Currency = request.Currency,
|
Currency = request.Currency,
|
||||||
Template = request.Template != null ? AppService.SerializeTemplate(AppService.Parse(request.Template)) : null,
|
Template = request.Template != null ? AppService.SerializeTemplate(AppService.Parse(request.Template)) : null,
|
||||||
ButtonText = request.FixedAmountPayButtonText ?? PointOfSaleSettings.BUTTON_TEXT_DEF,
|
ButtonText = request.FixedAmountPayButtonText ?? PointOfSaleSettings.BUTTON_TEXT_DEF,
|
||||||
CustomButtonText = request.CustomAmountPayButtonText ?? PointOfSaleSettings.CUSTOM_BUTTON_TEXT_DEF,
|
CustomButtonText = request.CustomAmountPayButtonText ?? PointOfSaleSettings.CUSTOM_BUTTON_TEXT_DEF,
|
||||||
CustomTipText = request.TipText ?? PointOfSaleSettings.CUSTOM_TIP_TEXT_DEF,
|
CustomTipText = request.TipText ?? PointOfSaleSettings.CUSTOM_TIP_TEXT_DEF,
|
||||||
|
CustomTipPercentages = request.CustomTipPercentages,
|
||||||
NotificationUrl = request.NotificationUrl,
|
NotificationUrl = request.NotificationUrl,
|
||||||
RedirectUrl = request.RedirectUrl,
|
RedirectUrl = request.RedirectUrl,
|
||||||
Description = request.Description,
|
Description = request.Description,
|
||||||
@@ -278,27 +295,27 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppDataBase ToModel(AppData appData)
|
private AppBaseData ToModel(AppData appData)
|
||||||
{
|
{
|
||||||
return new AppDataBase
|
return new AppBaseData
|
||||||
{
|
{
|
||||||
Id = appData.Id,
|
Id = appData.Id,
|
||||||
Archived = appData.Archived,
|
Archived = appData.Archived,
|
||||||
AppType = appData.AppType,
|
AppType = appData.AppType,
|
||||||
Name = appData.Name,
|
AppName = appData.Name,
|
||||||
StoreId = appData.StoreDataId,
|
StoreId = appData.StoreDataId,
|
||||||
Created = appData.Created,
|
Created = appData.Created,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppDataBase ToModel(Models.AppViewModels.ListAppsViewModel.ListAppViewModel appData)
|
private AppBaseData ToModel(Models.AppViewModels.ListAppsViewModel.ListAppViewModel appData)
|
||||||
{
|
{
|
||||||
return new AppDataBase
|
return new AppBaseData
|
||||||
{
|
{
|
||||||
Id = appData.Id,
|
Id = appData.Id,
|
||||||
Archived = appData.Archived,
|
Archived = appData.Archived,
|
||||||
AppType = appData.AppType,
|
AppType = appData.AppType,
|
||||||
Name = appData.AppName,
|
AppName = appData.AppName,
|
||||||
StoreId = appData.StoreId,
|
StoreId = appData.StoreId,
|
||||||
Created = appData.Created,
|
Created = appData.Created,
|
||||||
};
|
};
|
||||||
@@ -307,17 +324,18 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
private PointOfSaleAppData ToPointOfSaleModel(AppData appData)
|
private PointOfSaleAppData ToPointOfSaleModel(AppData appData)
|
||||||
{
|
{
|
||||||
var settings = appData.GetSettings<PointOfSaleSettings>();
|
var settings = appData.GetSettings<PointOfSaleSettings>();
|
||||||
|
Enum.TryParse<PosViewType>(settings.DefaultView.ToString(), true, out var defaultView);
|
||||||
|
|
||||||
return new PointOfSaleAppData
|
return new PointOfSaleAppData
|
||||||
{
|
{
|
||||||
Id = appData.Id,
|
Id = appData.Id,
|
||||||
Archived = appData.Archived,
|
Archived = appData.Archived,
|
||||||
AppType = appData.AppType,
|
AppType = appData.AppType,
|
||||||
Name = appData.Name,
|
AppName = appData.Name,
|
||||||
StoreId = appData.StoreDataId,
|
StoreId = appData.StoreDataId,
|
||||||
Created = appData.Created,
|
Created = appData.Created,
|
||||||
Title = settings.Title,
|
Title = settings.Title,
|
||||||
DefaultView = settings.DefaultView.ToString(),
|
DefaultView = defaultView,
|
||||||
ShowItems = settings.ShowItems,
|
ShowItems = settings.ShowItems,
|
||||||
ShowCustomAmount = settings.ShowCustomAmount,
|
ShowCustomAmount = settings.ShowCustomAmount,
|
||||||
ShowDiscount = settings.ShowDiscount,
|
ShowDiscount = settings.ShowDiscount,
|
||||||
@@ -325,28 +343,30 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
ShowCategories = settings.ShowCategories,
|
ShowCategories = settings.ShowCategories,
|
||||||
EnableTips = settings.EnableTips,
|
EnableTips = settings.EnableTips,
|
||||||
Currency = settings.Currency,
|
Currency = settings.Currency,
|
||||||
|
FixedAmountPayButtonText = settings.ButtonText,
|
||||||
|
CustomAmountPayButtonText = settings.CustomButtonText,
|
||||||
|
TipText = settings.CustomTipText,
|
||||||
|
CustomTipPercentages = settings.CustomTipPercentages,
|
||||||
|
FormId = settings.FormId,
|
||||||
|
NotificationUrl = settings.NotificationUrl,
|
||||||
|
RedirectUrl = settings.RedirectUrl,
|
||||||
|
Description = settings.Description,
|
||||||
|
RedirectAutomatically = settings.RedirectAutomatically,
|
||||||
Items = JsonConvert.DeserializeObject(
|
Items = JsonConvert.DeserializeObject(
|
||||||
JsonConvert.SerializeObject(
|
JsonConvert.SerializeObject(
|
||||||
AppService.Parse(settings.Template),
|
AppService.Parse(settings.Template),
|
||||||
new JsonSerializerSettings
|
new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
ContractResolver =
|
||||||
|
new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
FixedAmountPayButtonText = settings.ButtonText,
|
|
||||||
CustomAmountPayButtonText = settings.CustomButtonText,
|
|
||||||
TipText = settings.CustomTipText,
|
|
||||||
NotificationUrl = settings.NotificationUrl,
|
|
||||||
RedirectUrl = settings.RedirectUrl,
|
|
||||||
Description = settings.Description,
|
|
||||||
RedirectAutomatically = settings.RedirectAutomatically ?? false,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IActionResult? ValidatePOSAppRequest(CreatePointOfSaleAppRequest request)
|
private void ValidatePOSAppRequest(PointOfSaleAppRequest request)
|
||||||
{
|
{
|
||||||
var validationResult = ValidateCreateAppRequest(request);
|
|
||||||
if (request.Currency != null && _currencies.GetCurrencyData(request.Currency, false) == null)
|
if (request.Currency != null && _currencies.GetCurrencyData(request.Currency, false) == null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.Currency), "Invalid currency");
|
ModelState.AddModelError(nameof(request.Currency), "Invalid currency");
|
||||||
@@ -364,25 +384,19 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
ModelState.AddModelError(nameof(request.Template), "Invalid template");
|
ModelState.AddModelError(nameof(request.Template), "Invalid template");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
validationResult = this.CreateValidationError(ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return validationResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CrowdfundAppData ToCrowdfundModel(AppData appData)
|
private CrowdfundAppData ToCrowdfundModel(AppData appData)
|
||||||
{
|
{
|
||||||
var settings = appData.GetSettings<CrowdfundSettings>();
|
var settings = appData.GetSettings<CrowdfundSettings>();
|
||||||
|
Enum.TryParse<CrowdfundResetEvery>(settings.ResetEvery.ToString(), true, out var resetEvery);
|
||||||
|
|
||||||
return new CrowdfundAppData
|
return new CrowdfundAppData
|
||||||
{
|
{
|
||||||
Id = appData.Id,
|
Id = appData.Id,
|
||||||
Archived = appData.Archived,
|
Archived = appData.Archived,
|
||||||
AppType = appData.AppType,
|
AppType = appData.AppType,
|
||||||
Name = appData.Name,
|
AppName = appData.Name,
|
||||||
StoreId = appData.StoreDataId,
|
StoreId = appData.StoreDataId,
|
||||||
Created = appData.Created,
|
Created = appData.Created,
|
||||||
Title = settings.Title,
|
Title = settings.Title,
|
||||||
@@ -396,6 +410,17 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
MainImageUrl = settings.MainImageUrl,
|
MainImageUrl = settings.MainImageUrl,
|
||||||
NotificationUrl = settings.NotificationUrl,
|
NotificationUrl = settings.NotificationUrl,
|
||||||
Tagline = settings.Tagline,
|
Tagline = settings.Tagline,
|
||||||
|
DisqusEnabled = settings.DisqusEnabled,
|
||||||
|
DisqusShortname = settings.DisqusShortname,
|
||||||
|
SoundsEnabled = settings.SoundsEnabled,
|
||||||
|
AnimationsEnabled = settings.AnimationsEnabled,
|
||||||
|
ResetEveryAmount = settings.ResetEveryAmount,
|
||||||
|
ResetEvery = resetEvery,
|
||||||
|
DisplayPerksValue = settings.DisplayPerksValue,
|
||||||
|
DisplayPerksRanking = settings.DisplayPerksRanking,
|
||||||
|
SortPerksByPopularity = settings.SortPerksByPopularity,
|
||||||
|
Sounds = settings.Sounds,
|
||||||
|
AnimationColors = settings.AnimationColors,
|
||||||
Perks = JsonConvert.DeserializeObject(
|
Perks = JsonConvert.DeserializeObject(
|
||||||
JsonConvert.SerializeObject(
|
JsonConvert.SerializeObject(
|
||||||
AppService.Parse(settings.PerksTemplate),
|
AppService.Parse(settings.PerksTemplate),
|
||||||
@@ -404,18 +429,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
DisqusEnabled = settings.DisqusEnabled,
|
|
||||||
DisqusShortname = settings.DisqusShortname,
|
|
||||||
SoundsEnabled = settings.SoundsEnabled,
|
|
||||||
AnimationsEnabled = settings.AnimationsEnabled,
|
|
||||||
ResetEveryAmount = settings.ResetEveryAmount,
|
|
||||||
ResetEvery = settings.ResetEvery.ToString(),
|
|
||||||
DisplayPerksValue = settings.DisplayPerksValue,
|
|
||||||
DisplayPerksRanking = settings.DisplayPerksRanking,
|
|
||||||
SortPerksByPopularity = settings.SortPerksByPopularity,
|
|
||||||
Sounds = settings.Sounds,
|
|
||||||
AnimationColors = settings.AnimationColors
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,14 +449,15 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
return arr.Select(s => s.Trim()).ToArray();
|
return arr.Select(s => s.Trim()).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IActionResult? ValidateCrowdfundAppRequest(CreateCrowdfundAppRequest request)
|
private void ValidateCrowdfundAppRequest(CrowdfundAppRequest request)
|
||||||
{
|
{
|
||||||
var validationResult = ValidateCreateAppRequest(request);
|
|
||||||
if (request.TargetCurrency != null && _currencies.GetCurrencyData(request.TargetCurrency, false) == null)
|
if (request.TargetCurrency != null && _currencies.GetCurrencyData(request.TargetCurrency, false) == null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.TargetCurrency), "Invalid currency");
|
ModelState.AddModelError(nameof(request.TargetCurrency), "Invalid currency");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.PerksTemplate != null)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Just checking if we can serialize
|
// Just checking if we can serialize
|
||||||
@@ -452,16 +467,19 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.PerksTemplate), "Invalid template");
|
ModelState.AddModelError(nameof(request.PerksTemplate), "Invalid template");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (request.ResetEvery != Client.Models.CrowdfundResetEvery.Never && request.StartDate == null)
|
if (request.ResetEvery.HasValue && request.ResetEvery != CrowdfundResetEvery.Never)
|
||||||
|
{
|
||||||
|
if (request.StartDate == null)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.StartDate), "A start date is needed when the goal resets every X amount of time");
|
ModelState.AddModelError(nameof(request.StartDate), "A start date is needed when the goal resets every X amount of time");
|
||||||
}
|
}
|
||||||
|
if (request.ResetEveryAmount <= 0)
|
||||||
if (request.ResetEvery != Client.Models.CrowdfundResetEvery.Never && request.ResetEveryAmount <= 0)
|
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.ResetEveryAmount), "You must reset the goal at a minimum of 1");
|
ModelState.AddModelError(nameof(request.ResetEveryAmount), "You must reset the goal at a minimum of 1");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (request.Sounds != null && ValidateStringArray(request.Sounds) == null)
|
if (request.Sounds != null && ValidateStringArray(request.Sounds) == null)
|
||||||
{
|
{
|
||||||
@@ -473,36 +491,22 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
ModelState.AddModelError(nameof(request.AnimationColors), "Animation colors must be a non-empty array of non-empty strings");
|
ModelState.AddModelError(nameof(request.AnimationColors), "Animation colors must be a non-empty array of non-empty strings");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.StartDate != null && request.EndDate != null && DateTimeOffset.Compare((DateTimeOffset)request.StartDate, (DateTimeOffset)request.EndDate!) > 0)
|
if (request is { StartDate: not null, EndDate: not null } && DateTimeOffset.Compare((DateTimeOffset)request.StartDate, (DateTimeOffset)request.EndDate!) > 0)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.EndDate), "End date cannot be before start date");
|
ModelState.AddModelError(nameof(request.EndDate), "End date cannot be before start date");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
{
|
|
||||||
validationResult = this.CreateValidationError(ModelState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return validationResult;
|
private void ValidateAppRequest(IAppRequest? request)
|
||||||
}
|
|
||||||
|
|
||||||
private IActionResult? ValidateCreateAppRequest(CreateAppRequest request)
|
|
||||||
{
|
{
|
||||||
if (request is null)
|
if (string.IsNullOrEmpty(request?.AppName))
|
||||||
{
|
|
||||||
return BadRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(request.AppName))
|
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.AppName), "App name is missing");
|
ModelState.AddModelError(nameof(request.AppName), "App name is missing");
|
||||||
}
|
}
|
||||||
else if (request.AppName.Length < 1 || request.AppName.Length > 50)
|
else if (request.AppName.Length is < 1 or > 50)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(request.AppName), "Name can only be between 1 and 50 characters");
|
ModelState.AddModelError(nameof(request.AppName), "App name can only be between 1 and 50 characters");
|
||||||
}
|
}
|
||||||
|
|
||||||
return !ModelState.IsValid ? this.CreateValidationError(ModelState) : null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1088,7 +1088,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
public override async Task<PointOfSaleAppData> CreatePointOfSaleApp(
|
public override async Task<PointOfSaleAppData> CreatePointOfSaleApp(
|
||||||
string storeId,
|
string storeId,
|
||||||
CreatePointOfSaleAppRequest request, CancellationToken token = default)
|
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<PointOfSaleAppData>(
|
return GetFromActionResult<PointOfSaleAppData>(
|
||||||
await GetController<GreenfieldAppsController>().CreatePointOfSaleApp(storeId, request));
|
await GetController<GreenfieldAppsController>().CreatePointOfSaleApp(storeId, request));
|
||||||
@@ -1096,7 +1096,7 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
public override async Task<PointOfSaleAppData> UpdatePointOfSaleApp(
|
public override async Task<PointOfSaleAppData> UpdatePointOfSaleApp(
|
||||||
string appId,
|
string appId,
|
||||||
CreatePointOfSaleAppRequest request, CancellationToken token = default)
|
PointOfSaleAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<PointOfSaleAppData>(
|
return GetFromActionResult<PointOfSaleAppData>(
|
||||||
await GetController<GreenfieldAppsController>().UpdatePointOfSaleApp(appId, request));
|
await GetController<GreenfieldAppsController>().UpdatePointOfSaleApp(appId, request));
|
||||||
@@ -1104,27 +1104,27 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
|
|
||||||
public override async Task<CrowdfundAppData> CreateCrowdfundApp(
|
public override async Task<CrowdfundAppData> CreateCrowdfundApp(
|
||||||
string storeId,
|
string storeId,
|
||||||
CreateCrowdfundAppRequest request, CancellationToken token = default)
|
CrowdfundAppRequest request, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<CrowdfundAppData>(
|
return GetFromActionResult<CrowdfundAppData>(
|
||||||
await GetController<GreenfieldAppsController>().CreateCrowdfundApp(storeId, request));
|
await GetController<GreenfieldAppsController>().CreateCrowdfundApp(storeId, request));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<AppDataBase> GetApp(string appId, CancellationToken token = default)
|
public override async Task<AppBaseData> GetApp(string appId, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<AppDataBase>(
|
return GetFromActionResult<AppBaseData>(
|
||||||
await GetController<GreenfieldAppsController>().GetApp(appId));
|
await GetController<GreenfieldAppsController>().GetApp(appId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<AppDataBase[]> GetAllApps(string storeId, CancellationToken token = default)
|
public override async Task<AppBaseData[]> GetAllApps(string storeId, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<AppDataBase[]>(
|
return GetFromActionResult<AppBaseData[]>(
|
||||||
await GetController<GreenfieldAppsController>().GetAllApps(storeId));
|
await GetController<GreenfieldAppsController>().GetAllApps(storeId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<AppDataBase[]> GetAllApps(CancellationToken token = default)
|
public override async Task<AppBaseData[]> GetAllApps(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return GetFromActionResult<AppDataBase[]>(
|
return GetFromActionResult<AppBaseData[]>(
|
||||||
await GetController<GreenfieldAppsController>().GetAllApps());
|
await GetController<GreenfieldAppsController>().GetAllApps());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using BTCPayServer.Plugins.PointOfSale.Controllers;
|
|||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using BTCPayServer.Services.Apps;
|
using BTCPayServer.Services.Apps;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using Ganss.Xss;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ namespace BTCPayServer.Services.Apps
|
|||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
public string TargetCurrency { get; set; }
|
public string TargetCurrency { get; set; }
|
||||||
|
|
||||||
decimal? _TargetAmount;
|
decimal? _TargetAmount;
|
||||||
public decimal? TargetAmount
|
public decimal? TargetAmount
|
||||||
{
|
{
|
||||||
@@ -41,16 +40,14 @@ namespace BTCPayServer.Services.Apps
|
|||||||
public bool DisplayPerksRanking { get; set; }
|
public bool DisplayPerksRanking { get; set; }
|
||||||
public bool DisplayPerksValue { get; set; }
|
public bool DisplayPerksValue { get; set; }
|
||||||
public bool SortPerksByPopularity { get; set; }
|
public bool SortPerksByPopularity { get; set; }
|
||||||
public string FormId { get; set; } = null;
|
public string FormId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public string[] AnimationColors { get; set; } =
|
public string[] AnimationColors { get; set; } =
|
||||||
{
|
[
|
||||||
"#FF6138", "#FFBE53", "#2980B9", "#282741"
|
"#FF6138", "#FFBE53", "#2980B9", "#282741"
|
||||||
};
|
];
|
||||||
|
|
||||||
public string[] Sounds { get; set; } =
|
public string[] Sounds { get; set; } =
|
||||||
{
|
[
|
||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/dominating.wav",
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/dominating.wav",
|
||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/doublekill.wav",
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/doublekill.wav",
|
||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/doublekill2.wav",
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/doublekill2.wav",
|
||||||
@@ -78,7 +75,7 @@ namespace BTCPayServer.Services.Apps
|
|||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/ultrakill.wav",
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/ultrakill.wav",
|
||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/unstoppable.wav",
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/unstoppable.wav",
|
||||||
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/whickedsick.wav"
|
"https://github.com/ClaudiuHKS/AdvancedQuakeSounds/tree/master/sound/AQS/whickedsick.wav"
|
||||||
};
|
];
|
||||||
}
|
}
|
||||||
public enum CrowdfundResetEvery
|
public enum CrowdfundResetEvery
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using BTCPayServer.Client.Models;
|
|
||||||
using BTCPayServer.Plugins.PointOfSale.Models;
|
using BTCPayServer.Plugins.PointOfSale.Models;
|
||||||
using PosViewType = BTCPayServer.Plugins.PointOfSale.PosViewType;
|
using PosViewType = BTCPayServer.Plugins.PointOfSale.PosViewType;
|
||||||
|
|
||||||
@@ -89,19 +88,17 @@ namespace BTCPayServer.Services.Apps
|
|||||||
public bool ShowItems { get; set; }
|
public bool ShowItems { get; set; }
|
||||||
public bool ShowCustomAmount { get; set; }
|
public bool ShowCustomAmount { get; set; }
|
||||||
public bool ShowDiscount { get; set; }
|
public bool ShowDiscount { get; set; }
|
||||||
public bool ShowSearch { get; set; } = true;
|
public bool ShowSearch { get; set; }
|
||||||
public bool ShowCategories { get; set; } = true;
|
public bool ShowCategories { get; set; }
|
||||||
public bool EnableTips { get; set; }
|
public bool EnableTips { get; set; }
|
||||||
|
public string FormId { get; set; }
|
||||||
public string FormId { get; set; } = null;
|
|
||||||
|
|
||||||
public const string BUTTON_TEXT_DEF = "Buy for {0}";
|
public const string BUTTON_TEXT_DEF = "Buy for {0}";
|
||||||
public string ButtonText { get; set; } = BUTTON_TEXT_DEF;
|
public string ButtonText { get; set; } = BUTTON_TEXT_DEF;
|
||||||
public const string CUSTOM_BUTTON_TEXT_DEF = "Pay";
|
public const string CUSTOM_BUTTON_TEXT_DEF = "Pay";
|
||||||
public string CustomButtonText { get; set; } = CUSTOM_BUTTON_TEXT_DEF;
|
public string CustomButtonText { get; set; } = CUSTOM_BUTTON_TEXT_DEF;
|
||||||
public const string CUSTOM_TIP_TEXT_DEF = "Do you want to leave a tip?";
|
public const string CUSTOM_TIP_TEXT_DEF = "Do you want to leave a tip?";
|
||||||
public string CustomTipText { get; set; } = CUSTOM_TIP_TEXT_DEF;
|
public string CustomTipText { get; set; } = CUSTOM_TIP_TEXT_DEF;
|
||||||
public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = new int[] { 15, 18, 20 };
|
public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = { 15, 18, 20 };
|
||||||
public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF;
|
public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF;
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public string NotificationUrl { get; set; }
|
public string NotificationUrl { get; set; }
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/CreatePointOfSaleAppRequest"
|
"$ref": "#/components/schemas/PointOfSaleAppRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/CreatePointOfSaleAppRequest"
|
"$ref": "#/components/schemas/PointOfSaleAppRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -223,7 +223,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/CreateCrowdfundAppRequest"
|
"$ref": "#/components/schemas/CrowdfundAppRequest"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/BasicAppData"
|
"$ref": "#/components/schemas/AppBaseData"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,7 +372,7 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/BasicAppData"
|
"$ref": "#/components/schemas/AppBaseData"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,7 +405,7 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/BasicAppData"
|
"$ref": "#/components/schemas/AppBaseData"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,10 +425,46 @@
|
|||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
"schemas": {
|
"schemas": {
|
||||||
"PointOfSaleAppData": {
|
"AppBaseData": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Id of the app",
|
||||||
|
"example": "3ki4jsAkN4u9rv1PUzj1odX4Nx7s"
|
||||||
|
},
|
||||||
|
"appName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name given to the app when it was created",
|
||||||
|
"example": "my test app"
|
||||||
|
},
|
||||||
|
"storeId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Id of the store to which the app belongs",
|
||||||
|
"example": "9CiNzKoANXxmk5ayZngSXrHTiVvvgCrwrpFQd4m2K776"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "integer",
|
||||||
|
"example": 1651554744,
|
||||||
|
"description": "UNIX timestamp for when the app was created"
|
||||||
|
},
|
||||||
|
"appType": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "PointOfSale",
|
||||||
|
"description": "Type of the app which was created"
|
||||||
|
},
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "If true, the app does not appear in the apps list by default.",
|
||||||
|
"default": false,
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PointOfSaleBaseData": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/components/schemas/BasicAppData"
|
"$ref": "#/components/schemas/AppBaseData"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -436,12 +472,14 @@
|
|||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Display title of the app",
|
"description": "Display title of the app",
|
||||||
"example": "My PoS app"
|
"example": "My PoS app",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "App description",
|
"description": "App description",
|
||||||
"example": "This is my amazing PoS app"
|
"example": "This is my amazing PoS app",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"defaultView": {
|
"defaultView": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -458,48 +496,132 @@
|
|||||||
"Cart",
|
"Cart",
|
||||||
"Light",
|
"Light",
|
||||||
"Print"
|
"Print"
|
||||||
]
|
],
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"showItems": {
|
"showItems": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Display item selection for keypad",
|
"description": "Display item selection for keypad",
|
||||||
"example": true
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"showCustomAmount": {
|
"showCustomAmount": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether the option to enter a custom amount is shown",
|
"description": "Whether the option to enter a custom amount is shown",
|
||||||
"example": true
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"showDiscount": {
|
"showDiscount": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether the option to enter a discount is shown",
|
"description": "Whether the option to enter a discount is shown",
|
||||||
"example": false
|
"example": false,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"showSearch": {
|
"showSearch": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Display the search bar",
|
"description": "Display the search bar",
|
||||||
"example": false,
|
"example": false,
|
||||||
"default": true
|
"default": true,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"showCategories": {
|
"showCategories": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Display the list of categories",
|
"description": "Display the list of categories",
|
||||||
"example": false,
|
"example": false,
|
||||||
"default": true
|
"default": true,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"enableTips": {
|
"enableTips": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether the option to enter a tip is shown",
|
"description": "Whether the option to enter a tip is shown",
|
||||||
"example": true
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"currency": {
|
"currency": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Currency used for the app",
|
"description": "Currency used for the app",
|
||||||
"example": "BTC"
|
"example": "BTC",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
|
"fixedAmountPayButtonText": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Payment button text template for items with a set price",
|
||||||
|
"example": "Buy for {0}",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"customAmountPayButtonText": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Payment button text which appears for items which allow user to input a custom amount",
|
||||||
|
"example": "Pay",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"tipText": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Prompt which appears next to the tip amount field if tipping is enabled",
|
||||||
|
"example": "Do you want to leave a tip?",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"customTipPercentages": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of predefined tip percentage amounts",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"default": [15,18,20],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"notificationUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"redirectUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL user is redirected to once invoice is paid",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"redirectAutomatically": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether user is redirected to specified redirect URL automatically after the invoice is paid",
|
||||||
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"formId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Form ID to request customer data",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PointOfSaleAppRequest": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/PointOfSaleBaseData"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"template": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "JSON of item available in the app"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PointOfSaleAppData": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/PointOfSaleBaseData"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "JSON object of app items",
|
"description": "JSON object of app items",
|
||||||
@@ -535,34 +657,169 @@
|
|||||||
"disabled": false
|
"disabled": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"fixedAmountPayButtonText": {
|
"CrowdfundBaseData": {
|
||||||
"type": "string",
|
"allOf": [
|
||||||
"description": "Payment button text template for items with a set price",
|
{
|
||||||
"example": "Buy for {0}"
|
"$ref": "#/components/schemas/AppBaseData"
|
||||||
},
|
},
|
||||||
"customAmountPayButtonText": {
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Payment button text which appears for items which allow user to input a custom amount",
|
"description": "Display title of the app",
|
||||||
"example": "Pay"
|
"example": "My crowdfund app",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"tipText": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Prompt which appears next to the tip amount field if tipping is enabled",
|
"description": "App description",
|
||||||
"example": "Do you want to leave a tip?"
|
"example": "My crowdfund description",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether the app is enabled to be viewed by everyone",
|
||||||
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"enforceTargetAmount": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether contributions over the set target amount are allowed",
|
||||||
|
"example": false,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"startDate": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "UNIX timestamp for crowdfund start time (https://www.unixtimestamp.com/)",
|
||||||
|
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
||||||
|
"example": 768658369,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"endDate": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "UNIX timestamp for crowdfund end time (https://www.unixtimestamp.com/)",
|
||||||
|
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
||||||
|
"example": 771336769,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"targetCurrency": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Target currency for the crowdfund",
|
||||||
|
"example": "BTC",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"targetAmount": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Target amount for the crowdfund",
|
||||||
|
"example": 420.69,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"mainImageUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL for image used as a cover image for the app",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"notificationUrl": {
|
"notificationUrl": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations"
|
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"redirectUrl": {
|
"tagline": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "URL user is redirected to once invoice is paid"
|
"description": "Tagline for the app displayed to user",
|
||||||
|
"example": "I can't believe it's not butter",
|
||||||
|
"nullable": true
|
||||||
},
|
},
|
||||||
"redirectAutomatically": {
|
"disqusEnabled": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Whether user is redirected to specified redirect URL automatically after the invoice is paid",
|
"description": "Whether Disqus is enabled for the app",
|
||||||
"example": true
|
"nullable": true
|
||||||
|
},
|
||||||
|
"disqusShortname": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Disqus shortname to used for the app",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"soundsEnabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether sounds on new contributions are enabled",
|
||||||
|
"example": false,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"animationsEnabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether background animations on new contributions are enabled",
|
||||||
|
"example": true,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"resetEveryAmount": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Contribution goal reset frequency amount",
|
||||||
|
"example": 1,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"resetEvery": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Contribution goal reset frequency",
|
||||||
|
"example": "Day",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"displayPerksValue": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether perk values are displayed",
|
||||||
|
"example": false,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"sortPerksByPopularity": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether perks are sorted by popularity",
|
||||||
|
"default": true,
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"sounds": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of custom sounds which can be used on new contributions",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"example": ["https://github.com/ClaudiuHKS/AdvancedQuakeSounds/raw/master/sound/AQS/doublekill.wav"],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"animationColors": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Array of custom HEX colors which can be used for background animations on new contributions",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"example": ["#FF0000", "#00FF00", "#0000FF"],
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"formId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Form ID to request customer data",
|
||||||
|
"nullable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"CrowdfundAppRequest": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/CrowdfundBaseData"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"perksTemplate": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "JSON of perks available in the app"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -571,57 +828,11 @@
|
|||||||
"CrowdfundAppData": {
|
"CrowdfundAppData": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/components/schemas/BasicAppData"
|
"$ref": "#/components/schemas/CrowdfundBaseData"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Display title of the app",
|
|
||||||
"example": "My crowdfund app"
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "App description",
|
|
||||||
"example": "My crowdfund description"
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether the app is enabled to be viewed by everyone",
|
|
||||||
"example": true
|
|
||||||
},
|
|
||||||
"enforceTargetAmount": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether contributions over the set target amount are allowed",
|
|
||||||
"example": false
|
|
||||||
},
|
|
||||||
"startDate": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "UNIX timestamp for crowdfund start time (https://www.unixtimestamp.com/)",
|
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
|
||||||
"example": 768658369
|
|
||||||
},
|
|
||||||
"endDate": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "UNIX timestamp for crowdfund end time (https://www.unixtimestamp.com/)",
|
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
|
||||||
"example": 771336769
|
|
||||||
},
|
|
||||||
"targetCurrency": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Target currency for the crowdfund",
|
|
||||||
"example": "BTC"
|
|
||||||
},
|
|
||||||
"targetAmount": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "Target amount for the crowdfund",
|
|
||||||
"example": 420.69
|
|
||||||
},
|
|
||||||
"mainImageUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "URL for image used as a cover image for the app"
|
|
||||||
},
|
|
||||||
"perks": {
|
"perks": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "JSON of perks available in the app",
|
"description": "JSON of perks available in the app",
|
||||||
@@ -672,369 +883,10 @@
|
|||||||
"disabled": true
|
"disabled": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"notificationUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations"
|
|
||||||
},
|
|
||||||
"tagline": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Tagline for the app displayed to user",
|
|
||||||
"example": "I can't believe it's not butter"
|
|
||||||
},
|
|
||||||
"disqusEnabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether Disqus is enabled for the app"
|
|
||||||
},
|
|
||||||
"disqusShortname": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Disqus shortname to used for the app"
|
|
||||||
},
|
|
||||||
"soundsEnabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether sounds on new contributions are enabled",
|
|
||||||
"example": false
|
|
||||||
},
|
|
||||||
"animationsEnabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether background animations on new contributions are enabled",
|
|
||||||
"example": true
|
|
||||||
},
|
|
||||||
"resetEveryAmount": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "Contribution goal reset frequency amount",
|
|
||||||
"example": 1
|
|
||||||
},
|
|
||||||
"resetEvery": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Contribution goal reset frequency",
|
|
||||||
"example": "Day"
|
|
||||||
},
|
|
||||||
"displayPerksValue": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether perk values are displayed",
|
|
||||||
"example": false
|
|
||||||
},
|
|
||||||
"sortPerksByPopularity": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether perks are sorted by popularity",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"sounds": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Array of custom sounds which can be used on new contributions",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"example": ["https://github.com/ClaudiuHKS/AdvancedQuakeSounds/raw/master/sound/AQS/doublekill.wav"]
|
|
||||||
},
|
|
||||||
"animationColors": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Array of custom HEX colors which can be used for background animations on new contributions",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"example": ["#FF0000", "#00FF00", "#0000FF"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"BasicAppData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Id of the app",
|
|
||||||
"example": "3ki4jsAkN4u9rv1PUzj1odX4Nx7s"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Name given to the app when it was created",
|
|
||||||
"example": "my test app"
|
|
||||||
},
|
|
||||||
"storeId": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Id of the store to which the app belongs",
|
|
||||||
"example": "9CiNzKoANXxmk5ayZngSXrHTiVvvgCrwrpFQd4m2K776"
|
|
||||||
},
|
|
||||||
"created": {
|
|
||||||
"type": "integer",
|
|
||||||
"example": 1651554744,
|
|
||||||
"description": "UNIX timestamp for when the app was created"
|
|
||||||
},
|
|
||||||
"appType": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "PointOfSale",
|
|
||||||
"description": "Type of the app which was created"
|
|
||||||
},
|
|
||||||
"archived": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "If true, the app does not appear in the apps list by default.",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CreatePointOfSaleAppRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"appName": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the app (shown in admin UI)",
|
|
||||||
"nullable": false
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The title of the app (shown to the user)",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The description of the app",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"template": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Template for items available in the app",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"defaultView": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Template for items available in the app",
|
|
||||||
"nullable": true,
|
|
||||||
"x-enumNames": [
|
|
||||||
"Static",
|
|
||||||
"Cart",
|
|
||||||
"Light",
|
|
||||||
"Print"
|
|
||||||
],
|
|
||||||
"enum": [
|
|
||||||
"Static",
|
|
||||||
"Cart",
|
|
||||||
"Light",
|
|
||||||
"Print"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"currency": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Currency to use for the app. Defaults to the currency used by the store if not specified",
|
|
||||||
"example": "BTC",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"showCustomAmount": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to include a special item in the store which allows user to input a custom payment amount",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"showDiscount": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to allow user to input a discount amount. Applies to Cart view only. Not recommended for customer self-checkout",
|
|
||||||
"default": true,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"enableTips": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to allow user to input a tip amount. Applies to Cart and Light views only",
|
|
||||||
"default": true,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"customAmountPayButtonText": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Payment button text which appears for items which allow user to input a custom amount",
|
|
||||||
"default": "Pay",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"fixedAmountPayButtonText": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Payment button text which appears for items which have a fixed price",
|
|
||||||
"default": "Buy for {PRICE_HERE}",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"tipText": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Prompt which appears next to the tip amount field if tipping is enabled",
|
|
||||||
"default": "Do you want to leave a tip?",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"notificationUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"redirectUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "URL to redirect user to once invoice is paid",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"redirectAutomatically": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to redirect user to redirect URL automatically once invoice is paid. Defaults to what is set in the store settings",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"formId": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Form ID to request customer data",
|
|
||||||
"nullable": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"CreateCrowdfundAppRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"appName": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the app (shown in admin UI)",
|
|
||||||
"example": "Kukkstarter",
|
|
||||||
"nullable": false
|
|
||||||
},
|
|
||||||
"title": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The title of the app (shown to the user)",
|
|
||||||
"example": "My crowdfund app",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The description of the app (shown to the user)",
|
|
||||||
"example": "My app description",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Determines if the app is enabled to be viewed by everyone",
|
|
||||||
"default": true,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"enforceTargetAmount": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Will not allow contributions over the set target amount",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"startDate": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "UNIX timestamp for crowdfund start time (https://www.unixtimestamp.com/)",
|
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
|
||||||
"example": 768658369,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"endDate": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "UNIX timestamp for crowdfund end time (https://www.unixtimestamp.com/)",
|
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}],
|
|
||||||
"example": 771336769,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"targetCurrency": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Target currency for the crowdfund. Defaults to the currency used by the store if not specified",
|
|
||||||
"example": "BTC",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"targetAmount": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "Target amount for the crowdfund",
|
|
||||||
"example": 420,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"mainImageUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "URL for image to be used as a cover image for the app",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"perksTemplate": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "YAML template of perks available in the app",
|
|
||||||
"example": "test_perk:\r\n price: 100\r\n title: test perk\r\n price_type: \"fixed\" \r\n disabled: false",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"notificationUrl": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Callback notification url to POST to once when invoice is paid for and once when there are enough blockchain confirmations",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"tagline": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Tagline for the app (shown to the user)",
|
|
||||||
"example": "I can't believe it's not butter",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"disqusShortname": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Disqus shortname to used for the app. Enables Disqus functionality if set.",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"soundsEnabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Enables sounds on new contributions if set to true",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"animationsEnabled": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Enables background animations on new contributions if set to true",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"resetEveryAmount": {
|
|
||||||
"type": "number",
|
|
||||||
"description": "Contribution goal reset frequency amount. Must be used in conjunction with resetEvery and startDate.",
|
|
||||||
"default": 1,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"resetEvery": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Contribution goal reset frequency. Must be used in conjunction with resetEveryAmount and startDate.",
|
|
||||||
"nullable": true,
|
|
||||||
"default": "Never",
|
|
||||||
"x-enumNames": [
|
|
||||||
"Never",
|
|
||||||
"Hour",
|
|
||||||
"Day",
|
|
||||||
"Month",
|
|
||||||
"Year"
|
|
||||||
],
|
|
||||||
"enum": [
|
|
||||||
"Never",
|
|
||||||
"Hour",
|
|
||||||
"Day",
|
|
||||||
"Month",
|
|
||||||
"Year"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"displayPerksValue": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Displays values of perks if set to true",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"sortPerksByPopularity": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Sorts perks by popularity if set to true",
|
|
||||||
"default": false,
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"sounds": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Array of custom sounds to use on new contributions",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"nullable": true,
|
|
||||||
"example": [ "https://github.com/ClaudiuHKS/AdvancedQuakeSounds/raw/master/sound/AQS/doublekill.wav" ]
|
|
||||||
},
|
|
||||||
"animationColors": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Array of custom HEX colors to use for background animations on new contributions",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"nullable": true,
|
|
||||||
"example": ["#FF0000", "#00FF00", "#0000FF"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user