Browse Source

WIP billing

tags/5.1.0
Teknikode 3 months ago
parent
commit
84e41499be
35 changed files with 681 additions and 14 deletions
  1. 17
    0
      BillingCore/BillingCore.csproj
  2. 30
    0
      BillingCore/BillingService.cs
  3. 17
    0
      BillingCore/IBillingService.cs
  4. 14
    0
      BillingCore/IntervalType.cs
  5. 15
    0
      BillingCore/Product.cs
  6. 84
    0
      BillingCore/StripeService.cs
  7. 16
    0
      BillingCore/Subscription.cs
  8. 17
    0
      BillingCore/UserSubscription.cs
  9. 20
    0
      BillingService/ArgumentOptions.cs
  10. 19
    0
      BillingService/BillingService.csproj
  11. 77
    0
      BillingService/Program.cs
  12. 20
    0
      Configuration/BillingConfig.cs
  13. 6
    1
      Configuration/Config.cs
  14. 1
    1
      ServiceWorker/Program.cs
  15. 1
    1
      StorageService/IStorageService.cs
  16. 1
    1
      StorageService/LocalStorageService.cs
  17. 1
    1
      StorageService/MemoryStorageService.cs
  18. 1
    1
      StorageService/StorageService.cs
  19. 3
    1
      StorageService/StorageService.csproj
  20. 1
    1
      StorageService/StorageServiceFactory.cs
  21. 17
    1
      Teknik.sln
  22. 44
    0
      Teknik/App_Data/endpointMappings.json
  23. 39
    0
      Teknik/Areas/Billing/Controllers/BillingController.cs
  24. 13
    0
      Teknik/Areas/Billing/ViewModels/BillingViewModel.cs
  25. 19
    0
      Teknik/Areas/Billing/ViewModels/PaymentViewModel.cs
  26. 54
    0
      Teknik/Areas/Billing/Views/Billing/PaymentDetails.cshtml
  27. 89
    0
      Teknik/Areas/Billing/Views/Billing/Subscriptions.cshtml
  28. 14
    0
      Teknik/Areas/Billing/Views/Billing/ViewPaymentInfo.cshtml
  29. 1
    1
      Teknik/Areas/Paste/Controllers/PasteController.cs
  30. 1
    1
      Teknik/Areas/Paste/PasteHelper.cs
  31. 1
    1
      Teknik/Areas/Upload/Controllers/UploadController.cs
  32. 1
    1
      Teknik/Areas/Upload/UploadHelper.cs
  33. 1
    1
      Teknik/Areas/Vault/Controllers/VaultController.cs
  34. 20
    0
      Teknik/Scripts/Billing/Billing.js
  35. 6
    0
      Teknik/bundleconfig.json

+ 17
- 0
BillingCore/BillingCore.csproj View 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
- 0
BillingCore/BillingService.cs View 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
- 0
BillingCore/IBillingService.cs View 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
- 0
BillingCore/IntervalType.cs View 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
- 0
BillingCore/Product.cs View 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
- 0
BillingCore/StripeService.cs View 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
- 0
BillingCore/Subscription.cs View 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
- 0
BillingCore/UserSubscription.cs View 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
- 0
BillingService/ArgumentOptions.cs View 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
- 0
BillingService/BillingService.csproj View 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
- 0
BillingService/Program.cs View 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
- 0
Configuration/BillingConfig.cs View 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;
}
}
}

+ 6
- 1
Configuration/Config.cs View File

@@ -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
- 1
ServiceWorker/Program.cs View File

@@ -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;


+ 1
- 1
StorageService/IStorageService.cs View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using Teknik.Configuration;

namespace StorageService
namespace Teknik.StorageService
{
public interface IStorageService
{

+ 1
- 1
StorageService/LocalStorageService.cs View File

@@ -8,7 +8,7 @@ using Teknik.Configuration;
using Teknik.Utilities;
using Teknik.Utilities.Cryptography;

namespace StorageService
namespace Teknik.StorageService
{
public class LocalStorageService : StorageService
{

+ 1
- 1
StorageService/MemoryStorageService.cs View File

@@ -8,7 +8,7 @@ using Teknik.Configuration;
using Teknik.Utilities;
using Teknik.Utilities.Cryptography;

namespace StorageService
namespace Teknik.StorageService
{
public class MemoryStorageService : StorageService
{

+ 1
- 1
StorageService/StorageService.cs View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using Teknik.Configuration;

namespace StorageService
namespace Teknik.StorageService
{
public abstract class StorageService : IStorageService
{

+ 3
- 1
StorageService/StorageService.csproj View File

@@ -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>

+ 1
- 1
StorageService/StorageServiceFactory.cs View File

@@ -5,7 +5,7 @@ using System.Text;
using System.Threading.Tasks;
using Teknik.Configuration;

namespace StorageService
namespace Teknik.StorageService
{
public static class StorageServiceFactory
{

+ 17
- 1
Teknik.sln View File

@@ -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

+ 44
- 0
Teknik/App_Data/endpointMappings.json View File

@@ -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
- 0
Teknik/Areas/Billing/Controllers/BillingController.cs View 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
- 0
Teknik/Areas/Billing/ViewModels/BillingViewModel.cs View 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
- 0
Teknik/Areas/Billing/ViewModels/PaymentViewModel.cs View 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
- 0
Teknik/Areas/Billing/Views/Billing/PaymentDetails.cshtml View 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">&times;</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
- 0
Teknik/Areas/Billing/Views/Billing/Subscriptions.cshtml View 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
- 0
Teknik/Areas/Billing/Views/Billing/ViewPaymentInfo.cshtml View 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>

+ 1
- 1
Teknik/Areas/Paste/Controllers/PasteController.cs View File

@@ -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
{

+ 1
- 1
Teknik/Areas/Paste/PasteHelper.cs View File

@@ -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;


+ 1
- 1
Teknik/Areas/Upload/Controllers/UploadController.cs View File

@@ -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
{

+ 1
- 1
Teknik/Areas/Upload/UploadHelper.cs View File

@@ -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;


+ 1
- 1
Teknik/Areas/Vault/Controllers/VaultController.cs View File

@@ -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
- 0
Teknik/Scripts/Billing/Billing.js View 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 = '';
}
}

+ 6
- 0
Teknik/bundleconfig.json View File

@@ -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…
Cancel
Save