mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
WIP billing
This commit is contained in:
parent
3d7fbd6054
commit
84e41499be
17
BillingCore/BillingCore.csproj
Normal file
17
BillingCore/BillingCore.csproj
Normal file
@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Teknik.BillingCore</AssemblyName>
|
||||
<RootNamespace>Teknik.BillingCore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Stripe.net" Version="39.62.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Configuration\Configuration.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
30
BillingCore/BillingService.cs
Normal file
30
BillingCore/BillingService.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Configuration;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public abstract class BillingService
|
||||
{
|
||||
protected readonly BillingConfig Config;
|
||||
|
||||
public BillingService(BillingConfig billingConfig)
|
||||
{
|
||||
Config = billingConfig;
|
||||
}
|
||||
|
||||
public abstract bool CreateCustomer(string email);
|
||||
public abstract Tuple<bool, string, string> CreateSubscription(string customerId, string priceId);
|
||||
|
||||
public abstract bool EditSubscription();
|
||||
|
||||
public abstract Subscription GetSubscription(string subscriptionId);
|
||||
|
||||
public abstract bool RemoveSubscription();
|
||||
|
||||
public abstract void SyncSubscriptions();
|
||||
}
|
||||
}
|
17
BillingCore/IBillingService.cs
Normal file
17
BillingCore/IBillingService.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public interface IBillingService
|
||||
{
|
||||
public bool AddSubscription();
|
||||
public bool EditSubscription();
|
||||
public bool RemoveSubscription();
|
||||
public void GetSubscription();
|
||||
public void SyncSubscriptions();
|
||||
}
|
||||
}
|
14
BillingCore/IntervalType.cs
Normal file
14
BillingCore/IntervalType.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public enum IntervalType
|
||||
{
|
||||
Monthly,
|
||||
Yearly
|
||||
}
|
||||
}
|
15
BillingCore/Product.cs
Normal file
15
BillingCore/Product.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public class Product
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
84
BillingCore/StripeService.cs
Normal file
84
BillingCore/StripeService.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using Stripe;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Configuration;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public class StripeService : BillingService
|
||||
{
|
||||
public StripeService(BillingConfig config) : base(config)
|
||||
{ }
|
||||
|
||||
public override bool CreateCustomer(string email)
|
||||
{
|
||||
var options = new CustomerCreateOptions
|
||||
{
|
||||
Email = email,
|
||||
};
|
||||
var service = new CustomerService();
|
||||
var customer = service.Create(options);
|
||||
return customer != null;
|
||||
}
|
||||
|
||||
public override Subscription GetSubscription(string subscriptionId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override Tuple<bool, string, string> CreateSubscription(string customerId, string priceId)
|
||||
{
|
||||
// Create the subscription. Note we're expanding the Subscription's
|
||||
// latest invoice and that invoice's payment_intent
|
||||
// so we can pass it to the front end to confirm the payment
|
||||
var subscriptionOptions = new SubscriptionCreateOptions
|
||||
{
|
||||
Customer = customerId,
|
||||
Items = new List<SubscriptionItemOptions>
|
||||
{
|
||||
new SubscriptionItemOptions
|
||||
{
|
||||
Price = priceId,
|
||||
},
|
||||
},
|
||||
PaymentBehavior = "default_incomplete",
|
||||
};
|
||||
subscriptionOptions.AddExpand("latest_invoice.payment_intent");
|
||||
var subscriptionService = new SubscriptionService();
|
||||
try
|
||||
{
|
||||
Stripe.Subscription subscription = subscriptionService.Create(subscriptionOptions);
|
||||
|
||||
return new Tuple<bool, string, string>(true, subscription.Id, subscription.LatestInvoice.PaymentIntent.ClientSecret);
|
||||
}
|
||||
catch (StripeException e)
|
||||
{
|
||||
return new Tuple<bool, string, string>(false, $"Failed to create subscription. {e}", null);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool EditSubscription()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool RemoveSubscription()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SyncSubscriptions()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Customer GetCustomer(string id)
|
||||
{
|
||||
var service = new CustomerService();
|
||||
return service.Get(id);
|
||||
}
|
||||
}
|
||||
}
|
16
BillingCore/Subscription.cs
Normal file
16
BillingCore/Subscription.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public class Subscription
|
||||
{
|
||||
public int SubscriptionId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public double Amount { get; set; }
|
||||
}
|
||||
}
|
17
BillingCore/UserSubscription.cs
Normal file
17
BillingCore/UserSubscription.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.BillingCore
|
||||
{
|
||||
public class UserSubscription
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public int SubscriptionId { get; set; }
|
||||
public Subscription Subscription { get; set; }
|
||||
public int ProductId { get; set; }
|
||||
public Product Product { get; set; }
|
||||
}
|
||||
}
|
20
BillingService/ArgumentOptions.cs
Normal file
20
BillingService/ArgumentOptions.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using CommandLine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Teknik.BillingService
|
||||
{
|
||||
public class ArgumentOptions
|
||||
{
|
||||
[Option('s', "sync", Default = false, Required = false, HelpText = "Syncs the current subscriptions with the invoice system")]
|
||||
public bool SyncSubscriptions { get; set; }
|
||||
|
||||
[Option('c', "config", Required = false, HelpText = "The path to the teknik config file")]
|
||||
public string Config { get; set; }
|
||||
|
||||
// Omitting long name, default --verbose
|
||||
[Option(HelpText = "Prints all messages to standard output.")]
|
||||
public bool Verbose { get; set; }
|
||||
}
|
||||
}
|
19
BillingService/BillingService.csproj
Normal file
19
BillingService/BillingService.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>Teknik.BillingService</RootNamespace>
|
||||
<AssemblyName>Teknik.BillingService</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser.NS20" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Configuration\Configuration.csproj" />
|
||||
<ProjectReference Include="..\Teknik\Teknik.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
77
BillingService/Program.cs
Normal file
77
BillingService/Program.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using CommandLine;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Teknik.Configuration;
|
||||
using Teknik.Data;
|
||||
using Teknik.Utilities;
|
||||
|
||||
namespace Teknik.BillingService
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static string currentPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
private static string errorFile = Path.Combine(currentPath, "errorLogs.txt");
|
||||
private static string configPath = currentPath;
|
||||
|
||||
private static readonly object dbLock = new object();
|
||||
private static readonly object scanStatsLock = new object();
|
||||
|
||||
public static event Action<string> OutputEvent;
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
Parser.Default.ParseArguments<ArgumentOptions>(args).WithParsed(options =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(options.Config))
|
||||
configPath = options.Config;
|
||||
|
||||
if (Directory.Exists(configPath))
|
||||
{
|
||||
Config config = Config.Load(configPath);
|
||||
Output(string.Format("[{0}] Started Billing Service Process.", DateTime.Now));
|
||||
|
||||
var optionsBuilder = new DbContextOptionsBuilder<TeknikEntities>();
|
||||
optionsBuilder.UseSqlServer(config.DbConnection);
|
||||
|
||||
using (TeknikEntities db = new TeknikEntities(optionsBuilder.Options))
|
||||
{
|
||||
if (options.SyncSubscriptions)
|
||||
{
|
||||
// Sync subscription information
|
||||
}
|
||||
}
|
||||
|
||||
Output(string.Format("[{0}] Finished Billing Service Process.", DateTime.Now));
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = string.Format("[{0}] Config File does not exist.", DateTime.Now);
|
||||
File.AppendAllLines(errorFile, new List<string> { msg });
|
||||
Output(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = string.Format("[{0}] Exception: {1}", DateTime.Now, ex.GetFullMessage(true));
|
||||
File.AppendAllLines(errorFile, new List<string> { msg });
|
||||
Output(msg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void Output(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
if (OutputEvent != null)
|
||||
{
|
||||
OutputEvent(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
Configuration/BillingConfig.cs
Normal file
20
Configuration/BillingConfig.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Teknik.Configuration
|
||||
{
|
||||
public class BillingConfig
|
||||
{
|
||||
public string StripePublishApiKey { get; set; }
|
||||
public string StripeSecretApiKey { get; set; }
|
||||
|
||||
public BillingConfig()
|
||||
{
|
||||
StripePublishApiKey = null;
|
||||
StripeSecretApiKey = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ namespace Teknik.Configuration
|
||||
private LoggingConfig _LoggingConfig;
|
||||
private PiwikConfig _PiwikConfig;
|
||||
private IRCConfig _IRCConfig;
|
||||
private BillingConfig _BillingConfig;
|
||||
|
||||
public bool DevEnvironment { get { return _DevEnvironment; } set { _DevEnvironment = value; } }
|
||||
public bool Migrate { get { return _Migrate; } set { _Migrate = value; } }
|
||||
@ -120,9 +121,12 @@ namespace Teknik.Configuration
|
||||
// Piwik Configuration
|
||||
public PiwikConfig PiwikConfig { get { return _PiwikConfig; } set { _PiwikConfig = value; } }
|
||||
|
||||
// Piwik Configuration
|
||||
// IRC Configuration
|
||||
public IRCConfig IRCConfig { get { return _IRCConfig; } set { _IRCConfig = value; } }
|
||||
|
||||
// Billing Configuration
|
||||
public BillingConfig BillingConfig { get { return _BillingConfig; } set { _BillingConfig = value; } }
|
||||
|
||||
public Config()
|
||||
{
|
||||
_ConfigRWLock = new ReaderWriterLockSlim();
|
||||
@ -167,6 +171,7 @@ namespace Teknik.Configuration
|
||||
LoggingConfig = new LoggingConfig();
|
||||
PiwikConfig = new PiwikConfig();
|
||||
IRCConfig = new IRCConfig();
|
||||
BillingConfig = new BillingConfig();
|
||||
}
|
||||
|
||||
public static Config Deserialize(string text)
|
||||
|
@ -1,7 +1,6 @@
|
||||
using CommandLine;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using nClam;
|
||||
using StorageService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -17,6 +16,7 @@ using Teknik.Areas.Users.Models;
|
||||
using Teknik.Areas.Users.Utility;
|
||||
using Teknik.Configuration;
|
||||
using Teknik.Data;
|
||||
using Teknik.StorageService;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Teknik.Configuration;
|
||||
|
||||
namespace StorageService
|
||||
namespace Teknik.StorageService
|
||||
{
|
||||
public interface IStorageService
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using Teknik.Configuration;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
namespace StorageService
|
||||
namespace Teknik.StorageService
|
||||
{
|
||||
public class LocalStorageService : StorageService
|
||||
{
|
||||
|
@ -8,7 +8,7 @@ using Teknik.Configuration;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
|
||||
namespace StorageService
|
||||
namespace Teknik.StorageService
|
||||
{
|
||||
public class MemoryStorageService : StorageService
|
||||
{
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Teknik.Configuration;
|
||||
|
||||
namespace StorageService
|
||||
namespace Teknik.StorageService
|
||||
{
|
||||
public abstract class StorageService : IStorageService
|
||||
{
|
||||
|
@ -1,7 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>Teknik.StorageService</RootNamespace>
|
||||
<AssemblyName>Teknik.StorageService</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Configuration;
|
||||
|
||||
namespace StorageService
|
||||
namespace Teknik.StorageService
|
||||
{
|
||||
public static class StorageServiceFactory
|
||||
{
|
||||
|
18
Teknik.sln
18
Teknik.sln
@ -34,7 +34,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ContentScanningService", "C
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebCommon", "WebCommon\WebCommon.csproj", "{32E85A7F-871A-437C-9BA3-00499AAB442C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StorageService", "StorageService\StorageService.csproj", "{4A600C17-C772-462F-A37F-307E7893B2DB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageService", "StorageService\StorageService.csproj", "{4A600C17-C772-462F-A37F-307E7893B2DB}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BillingService", "BillingService\BillingService.csproj", "{AF417E48-8137-4677-9058-E4DD2745FEC5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BillingCore", "BillingCore\BillingCore.csproj", "{A9ED275B-4004-4A5B-8F1C-134A29B999E7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -115,6 +119,18 @@ Global
|
||||
{4A600C17-C772-462F-A37F-307E7893B2DB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A600C17-C772-462F-A37F-307E7893B2DB}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A600C17-C772-462F-A37F-307E7893B2DB}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF417E48-8137-4677-9058-E4DD2745FEC5}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Test|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9ED275B-4004-4A5B-8F1C-134A29B999E7}.Test|Any CPU.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1045,6 +1045,50 @@
|
||||
"action": "ViewRawPGP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Billing.Index",
|
||||
"HostTypes": [ "Full" ],
|
||||
"SubDomains": [ "billing" ],
|
||||
"Pattern": "",
|
||||
"Area": "Billing",
|
||||
"Defaults": {
|
||||
"controller": "Billing",
|
||||
"action": "Index"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Billing.Subscriptions",
|
||||
"HostTypes": [ "Full" ],
|
||||
"SubDomains": [ "billing" ],
|
||||
"Pattern": "Subscriptions",
|
||||
"Area": "Billing",
|
||||
"Defaults": {
|
||||
"controller": "Billing",
|
||||
"action": "Subscriptions"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Billing.ViewPaymentInfo",
|
||||
"HostTypes": [ "Full" ],
|
||||
"SubDomains": [ "billing" ],
|
||||
"Pattern": "PaymentInfo",
|
||||
"Area": "Billing",
|
||||
"Defaults": {
|
||||
"controller": "Billing",
|
||||
"action": "ViewPaymentInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Billing.Action",
|
||||
"HostTypes": [ "Full" ],
|
||||
"SubDomains": [ "billing" ],
|
||||
"Pattern": "Action/{action}",
|
||||
"Area": "Billing",
|
||||
"Defaults": {
|
||||
"controller": "Billing",
|
||||
"action": "Index"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "Vault.Index",
|
||||
"HostTypes": [ "Full" ],
|
||||
|
39
Teknik/Areas/Billing/Controllers/BillingController.cs
Normal file
39
Teknik/Areas/Billing/Controllers/BillingController.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.Areas.Billing.ViewModels;
|
||||
using Teknik.Configuration;
|
||||
using Teknik.Controllers;
|
||||
using Teknik.Data;
|
||||
using Teknik.Logging;
|
||||
|
||||
namespace Teknik.Areas.Billing.Controllers
|
||||
{
|
||||
[Area("Billing")]
|
||||
public class BillingController : DefaultController
|
||||
{
|
||||
public BillingController(ILogger<Logger> logger, Config config, TeknikEntities dbContext) : base(logger, config, dbContext) { }
|
||||
|
||||
[AllowAnonymous]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View(new BillingViewModel() { StripePublishKey = _config.BillingConfig.StripePublishApiKey });
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public IActionResult Subscriptions()
|
||||
{
|
||||
return View(new BillingViewModel() { StripePublishKey = _config.BillingConfig.StripePublishApiKey });
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public IActionResult ViewPaymentInfo()
|
||||
{
|
||||
return View(new PaymentViewModel() { StripePublishKey = _config.BillingConfig.StripePublishApiKey });
|
||||
}
|
||||
}
|
||||
}
|
13
Teknik/Areas/Billing/ViewModels/BillingViewModel.cs
Normal file
13
Teknik/Areas/Billing/ViewModels/BillingViewModel.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Billing.ViewModels
|
||||
{
|
||||
public class BillingViewModel : ViewModelBase
|
||||
{
|
||||
public string StripePublishKey { get; set; }
|
||||
}
|
||||
}
|
19
Teknik/Areas/Billing/ViewModels/PaymentViewModel.cs
Normal file
19
Teknik/Areas/Billing/ViewModels/PaymentViewModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Billing.ViewModels
|
||||
{
|
||||
public class PaymentViewModel : ViewModelBase
|
||||
{
|
||||
public string StripePublishKey { get; set; }
|
||||
public string PaymentName { get; set; }
|
||||
public string CreditCardNumber { get; set; }
|
||||
public string ExpirationMonth { get; set; }
|
||||
public string ExpirationYear { get; set; }
|
||||
public string CCV { get; set; }
|
||||
public string ZipCode { get; set; }
|
||||
}
|
||||
}
|
54
Teknik/Areas/Billing/Views/Billing/PaymentDetails.cshtml
Normal file
54
Teknik/Areas/Billing/Views/Billing/PaymentDetails.cshtml
Normal file
@ -0,0 +1,54 @@
|
||||
@model Teknik.Areas.Billing.ViewModels.PaymentViewModel
|
||||
|
||||
<script>
|
||||
var stripePublishKey = '@Model.StripePublishKey';
|
||||
var editURL = '@Url.SubRouteUrl("billing", "Billing.Action", new { action = "UpdatePayment" })';
|
||||
</script>
|
||||
|
||||
@{
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<div id="paymentStatus">
|
||||
@if (Model.Error)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>@Model.ErrorMessage</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="paymentForm" action="@Url.SubRouteUrl("billing", "Billing.UpdatePayment" )" method="post" accept-charset="UTF-8">
|
||||
<div class="form-group">
|
||||
<label for="paymentName">Full Name</label>
|
||||
<input type="text" class="form-control" id="paymentName" value="@Model.PaymentName" placeholder="Joe Smith" name="Payment.FullName" data-val-required="The Full Name of the card holder is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="paymentCardNumber">Credit Card Number</label>
|
||||
<input type="text" class="form-control" id="paymentCardNumber" value="@Model.CreditCardNumber" placeholder="XXXX-XXXX-XXXX-XXXX" name="Payment.CardNumber" data-val-required="The Credit Card Number is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="paymentExpMonth">Expiration Month</label>
|
||||
<input type="text" class="form-control" id="paymentExpMonth" value="@Model.ExpirationMonth" placeholder="MM" name="Payment.ExpMonth" data-val-required="The Expiration Month is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="paymentExpYear">Expiration Year</label>
|
||||
<input type="text" class="form-control" id="paymentExpYear" value="@Model.ExpirationYear" placeholder="YY" name="Payment.ExpYear" data-val-required="The Expiration Year is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="paymentCCV">CCV</label>
|
||||
<input type="text" class="form-control" id="paymentCCV" value="@Model.CCV" placeholder="123" name="Payment.CCV" data-val-required="The CCV is required." data-val="true" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="paymentZip">Zip Code</label>
|
||||
<input type="text" class="form-control" id="paymentZip" value="@Model.ZipCode" placeholder="99999" name="Payment.Zip" data-val-required="The Zip is required." data-val="true" />
|
||||
</div>
|
||||
<p class="text-center">
|
||||
By registering for Teknik, you agree to the <a href="@Url.SubRouteUrl(" tos", "TOS.Index" )" target="_blank">Terms of Service</a>.
|
||||
</p>
|
||||
<div class="form-group text-center">
|
||||
<button class="btn btn-primary" id="paymentSubmit" type="submit" name="Payment.Submit">Sign Up</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
<bundle src="js/billing.min.js" append-version="true"></bundle>
|
89
Teknik/Areas/Billing/Views/Billing/Subscriptions.cshtml
Normal file
89
Teknik/Areas/Billing/Views/Billing/Subscriptions.cshtml
Normal file
@ -0,0 +1,89 @@
|
||||
@model Teknik.Areas.Billing.ViewModels.BillingViewModel
|
||||
|
||||
@{
|
||||
string extraUsage = "If you need more than 100 GB of monthly upload bandwidth, please contact support for assistance.";
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<h2 class="text-center">Upload Bandwidth Subscriptions</h2>
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-md-3">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Basic Account</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>Free</h2>
|
||||
<h5>
|
||||
<small>No Overage Allowed</small>
|
||||
</h5>
|
||||
<p>
|
||||
<strong>5 GB</strong> Uploads <small class="text-muted">/ month</small>
|
||||
</p>
|
||||
<p><a href="@Url.SubRouteUrl("account", "User.Register")" class="btn btn-primary center-block" role="button">Sign up for free</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Standalone 10 GB</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>$0.99 <small>/ month</small></h2>
|
||||
<h5>
|
||||
<small>Overage at $0.30 / GB <span data-toggle="tooltip" data-placement="top" title="@extraUsage">(Up to 100 GB)*</span></small>
|
||||
</h5>
|
||||
<p>
|
||||
<strong>10 GB</strong> Uploads <small class="text-muted">/ month</small>
|
||||
</p>
|
||||
<p><a href="@Url.SubRouteUrl("billing", "Billing.Subscribe", new { plan = "10gb" })" class="btn btn-primary center-block" role="button">Subscribe</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">Standalone 50 GB</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>$3.99 <small>/ month</small></h2>
|
||||
<h5>
|
||||
<small>Overage at $0.30 / GB <span data-toggle="tooltip" data-placement="top" title="@extraUsage">(Up to 100 GB)*</span></small>
|
||||
</h5>
|
||||
<p>
|
||||
<strong>50 GB</strong> Uploads <small class="text-muted">/ month</small>
|
||||
</p>
|
||||
<p><a href="@Url.SubRouteUrl("billing", "Billing.Subscribe", new { plan = "50gb" })" class="btn btn-primary center-block" role="button">Subscribe</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-3">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">By Upload Usage</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<h2>$0.15 <small>/ GB</small></h2>
|
||||
<h5>
|
||||
<small>No Overage Fee</small>
|
||||
</h5>
|
||||
<p>
|
||||
<strong><span data-toggle="tooltip" data-placement="top" title="@extraUsage">Up to 100 GB*</span></strong> Uploads <small class="text-muted">/ month</small>
|
||||
</p>
|
||||
<p><a href="@Url.SubRouteUrl("billing", "Billing.Subscribe", new { plan = "usage" })" class="btn btn-primary center-block" role="button">Subscribe</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<p>
|
||||
<small>
|
||||
* @extraUsage
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
14
Teknik/Areas/Billing/Views/Billing/ViewPaymentInfo.cshtml
Normal file
14
Teknik/Areas/Billing/Views/Billing/ViewPaymentInfo.cshtml
Normal file
@ -0,0 +1,14 @@
|
||||
@model Teknik.Areas.Billing.ViewModels.PaymentViewModel
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="text-center">
|
||||
<h1>Payment Information</h1>
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
@await Html.PartialAsync("../../Areas/Billing/Views/Billing/PaymentDetails", Model)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -22,7 +22,7 @@ using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
using Teknik.Utilities.Routing;
|
||||
using StorageService;
|
||||
using Teknik.StorageService;
|
||||
|
||||
namespace Teknik.Areas.Paste.Controllers
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using Teknik.Models;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
using Teknik.Data;
|
||||
using System.IO;
|
||||
using StorageService;
|
||||
using Teknik.StorageService;
|
||||
using Teknik.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
@ -24,7 +24,7 @@ using Teknik.Logging;
|
||||
using Teknik.Areas.Users.Models;
|
||||
using Teknik.ContentScanningService;
|
||||
using Teknik.Utilities.Routing;
|
||||
using StorageService;
|
||||
using Teknik.StorageService;
|
||||
|
||||
namespace Teknik.Areas.Upload.Controllers
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using Teknik.Utilities;
|
||||
using System.Text;
|
||||
using Teknik.Utilities.Cryptography;
|
||||
using Teknik.Data;
|
||||
using StorageService;
|
||||
using Teknik.StorageService;
|
||||
using Teknik.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StorageService;
|
||||
using Teknik.StorageService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
20
Teknik/Scripts/Billing/Billing.js
Normal file
20
Teknik/Scripts/Billing/Billing.js
Normal file
@ -0,0 +1,20 @@
|
||||
// Set your publishable key: remember to change this to your live publishable key in production
|
||||
// See your keys here: https://dashboard.stripe.com/apikeys
|
||||
let stripe = Stripe(stripePublishKey);
|
||||
let elements = stripe.elements();
|
||||
|
||||
let card = elements.create('card');
|
||||
card.mount('#card-element');
|
||||
|
||||
card.on('change', function (event) {
|
||||
displayError(event);
|
||||
});
|
||||
function displayError(event) {
|
||||
changeLoadingStatePrices(false);
|
||||
let displayError = document.getElementById('card-element-errors');
|
||||
if (event.error) {
|
||||
displayError.textContent = event.error.message;
|
||||
} else {
|
||||
displayError.textContent = '';
|
||||
}
|
||||
}
|
@ -291,6 +291,12 @@
|
||||
"./wwwroot/lib/bootstrap/css/bootstrap-switch.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/billing.min.js",
|
||||
"inputFiles": [
|
||||
"./wwwroot/js/app/Billing/Billing.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/vault.min.js",
|
||||
"inputFiles": [
|
||||
|
Loading…
Reference in New Issue
Block a user