Copy base from mistoxwebsite
Docker Build and Release Upload / build (push) Has been cancelled

This commit is contained in:
2025-07-13 19:04:43 -07:00
parent a0e106c2bc
commit 22a30933ca
103 changed files with 13926 additions and 457 deletions
+285
View File
@@ -0,0 +1,285 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using BoredCareers.Services;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
namespace BoredCareers.Controllers {
[ApiController]
[Route("api/account/[controller]")]
public class AuthenticationController : MistoxControllerBase {
EmailService _emailContext;
public AuthenticationController(DatabaseService db, EmailService emailContext) : base(db) {
_emailContext = emailContext;
}
[Route("login")]
[HttpPost]
public async Task<ActionResult<Account>> Login([FromForm] string UserName, [FromForm] string PasswordHash, [FromForm] bool StayLoggedIn) {
try {
Account? test = await _databaseService.GetAccount(UserName.ToLower());
if (test != null) {
if (test.EmailVerified == true) {
if (test.FailedPasswordLock) {
if (test.CurrentPasswordAttempts >= test.PasswordAttempts) {
return new Account() { Error = "Too many failed password attempts. Please reset your password" };
}
}
if (BCrypt.Net.BCrypt.Verify(PasswordHash, test.PasswordHash)) {
test.CurrentPasswordAttempts = 0;
await _databaseService.SetAccount(test);
List<Claim> claims = new List<Claim>() {
new Claim("ID", test.ID.ToString())
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")),
new AuthenticationProperties {
ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on
IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn
}
);
return test;
}
else {
test.CurrentPasswordAttempts += 1;
await _databaseService.SetAccount(test);
return new Account() { Error = "Wrong password" };
}
}
else {
await SendVerify(test.UserName);
return new Account() { Error = "A new verify email has been sent. \n Note only 1 email send every 5 mintes" };
}
}
return new Account() { Error = "User doesn't exist" };
} catch (Exception ex) {
return new Account() { Error = ex.Message };
}
}
[Route("register")]
[HttpPost]
public async Task<ActionResult<Account>> Register([FromForm] string Email, [FromForm] string UserName, [FromForm] string PasswordHash) {
try {
if (await _databaseService.GetAccount(UserName.ToLower()) == null) {
if (await _databaseService.GetAccount(Email.ToLower()) == null) {
Account? created = new Account() {
UserName = UserName.ToLower(),
Email = Email.ToLower(),
EmailVerified = false,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(PasswordHash),
};
await _databaseService.SetAccount(created);
created = await _databaseService.GetAccount(Email.ToLower());
if (created != null) {
await SendVerify(created.UserName);
return created;
}
return new Account() { Error = "Unknown Error" };
}
else {
return new Account() { Error = "Email is already in use" };
}
}
else {
return new Account() { Error = "UserName is taken" };
}
} catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return new Account() { Error = ex.Message };
}
}
[Route("changepassword")]
[HttpPost]
public async Task<ActionResult<bool>> ChangePassword([FromForm] string OldPassword, [FromForm] string NewPassword) {
try {
if (isLoggedIn()) {
Account user = await getLoggedInUser();
if (BCrypt.Net.BCrypt.Verify(OldPassword, user.PasswordHash)) {
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
user.CurrentPasswordAttempts = 0;
await _databaseService.SetAccount(user);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("toggleaccountlock")]
[HttpPost]
public async Task<ActionResult<string>> ToggleAccountLock([FromForm] bool AccountLock) {
try {
if (isLoggedIn()) {
Account user = await getLoggedInUser();
user.FailedPasswordLock = AccountLock;
user.CurrentPasswordAttempts = 0;
await _databaseService.SetAccount(user);
return "Account Lock Status Updated";
}
return "Unknown Error Occurred";
} catch (Exception ex) {
return ex.Message;
}
}
[Route("get")]
[HttpPost]
public async Task<ActionResult<Account?>> Get() {
try {
if (isLoggedIn()) {
return await getLoggedInUser();
}
return Ok();
} catch {
return Ok();
}
}
[Route("logout")]
[HttpPost]
public async Task Logout() {
await HttpContext.SignOutAsync();
}
[Route("sendverifyemail")]
[HttpPost]
public async Task<ActionResult<string>> SendVerify([FromForm] string UserName) {
try {
string key = "v" + UserName;
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another verify email until 5 minutes has elapsed ";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _databaseService.GetAccount(UserName.ToLower());
if (test != null) {
test.EmailToken = Guid.NewGuid().ToString();
await _databaseService.SetAccount(test);
string EmailContents = EmailService.VerifyEmailEmail;
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@VerifyPassword", test.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account not found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
[Route("verifyemail")]
[HttpPost]
public async Task<ActionResult<bool>> VerifyEmail([FromForm] string UserName, [FromForm] string EmailToken) {
try {
Account? test = await _databaseService.GetAccount(UserName.ToLower());
if (test != null) {
if (!string.IsNullOrEmpty(test.EmailToken) && test.EmailToken == EmailToken) {
test.EmailToken = "";
test.EmailVerified = true;
await _databaseService.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("sendresetpassword")]
[HttpPost]
public async Task<ActionResult<string>> ResetPassword([FromForm] string Email) {
try {
string key = "p" + Email.ToLower();
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another reset requests until 5 minutes has elapsed";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _databaseService.GetAccount(Email.ToLower());
if (test != null) {
test.EmailToken = Guid.NewGuid().ToString();
await _databaseService.SetAccount(test);
string EmailContents = EmailService.ResetPasswordEmail;
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@ResetPassWord", test.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account Not Found";
} catch (Exception e) {
Console.WriteLine("EmailService Error: " + e.ToString());
return "The connection couldn't be established to the email server";
}
}
[Route("resetpassword")]
[HttpPost]
public async Task<ActionResult<bool>> ResetPwdVerify([FromForm] string UserName, [FromForm] string NewPassword, [FromForm] string ResetToken) {
try {
Account? test = await _databaseService.GetAccount(UserName.ToLower());
if (test != null && !string.IsNullOrEmpty(test.EmailToken)) {
if (!string.IsNullOrEmpty(test.EmailToken) && test.EmailToken == ResetToken) {
test.CurrentPasswordAttempts = 0;
test.EmailToken = "";
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
await _databaseService.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("delete")]
[HttpPost]
public async Task<ActionResult<bool>> delete([FromForm] string Password) {
try {
if (isLoggedIn()) {
Account user = await getLoggedInUser();
if (BCrypt.Net.BCrypt.Verify(Password, user.PasswordHash)) {
await _databaseService.DeleteAccount(user.ID);
return true;
}
}
return false;
} catch {
return false;
}
}
}
}
+69
View File
@@ -0,0 +1,69 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Entities;
using BoredCareers.Services.DatabaseService;
namespace BoredCareers.Controllers {
[ApiController]
[Route("api/cart/[controller]")]
public class CartController : MistoxControllerBase {
CartController(DatabaseService db) : base(db) { }
[Route("get")]
[HttpPost]
public async Task<ActionResult<Cart[]>> GetCart() {
try {
if (isLoggedIn()) {
return Ok(await _databaseService.GetCart(getLoggedInUserID()));
}
return StatusCode(500);
} catch {
return StatusCode(500);
}
}
[Route("add")]
[HttpPost]
public async Task<IActionResult> AddCart([FromBody] Cart cart) {
try {
if (isLoggedIn()) {
cart.AccountID = getLoggedInUserID();
await _databaseService.AddToCart(cart);
return Ok();
}
return StatusCode(500);
} catch {
return StatusCode(500);
}
}
[Route("remove")]
[HttpPost]
public async Task<IActionResult> RemoveCart([FromBody] Cart cart) {
try {
if (isLoggedIn()) {
cart.AccountID = getLoggedInUserID();
await _databaseService.RemoveFromCart(cart);
return Ok();
}
return StatusCode(500);
} catch {
return StatusCode(500);
}
}
[Route("clear")]
[HttpPost]
public async Task<IActionResult> ClearCart() {
try {
if (isLoggedIn()) {
await _databaseService.ClearCart(getLoggedInUserID());
return Ok();
}
return StatusCode(500);
} catch {
return StatusCode(500);
}
}
}
}
@@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Entities;
using BoredCareers.Services.DatabaseService;
namespace BoredCareers.Controllers {
public class MistoxControllerBase : ControllerBase {
public DatabaseService _databaseService;
public MistoxControllerBase(DatabaseService databaseService) {
_databaseService = databaseService;
}
public bool isLoggedIn() {
if (User.Identity != null && User.Identity.IsAuthenticated) {
return true;
}
return false;
}
public int getLoggedInUserID() {
return Convert.ToInt32(User.FindFirst("ID")?.Value);
}
public async Task<Account> getLoggedInUser() {
try {
Account? test = await _databaseService.GetAccount(getLoggedInUserID());
if (test != null) {
return test;
}
return new Account();
} catch {
return new Account();
}
}
public string Substitue(string message, string subString, string Replacement) {
for (int i = 0; i < (message.Length - subString.Length); i++) {
if (message.Substring(i, subString.Length) == subString) {
string before = message.Substring(0, i);
string after = message.Substring(i + subString.Length);
return before + Replacement + after;
}
}
return message;
}
public bool contains(string outer, string inner) {
if (outer.Length >= inner.Length) {
for (int i = 0; i < outer.Length - inner.Length; i++) {
if (outer.Substring(i, inner.Length) == inner) {
return true;
}
}
}
return false;
}
}
}
+68
View File
@@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Controllers.Payment;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
namespace BoredCareers.Controllers {
[ApiController]
[Route("api/payment/[controller]")]
public class PaymentController : MistoxControllerBase {
IPayment _paymentService;
public PaymentController(DatabaseService db) : base(db) {
if (IPayment._PaymentType == PaymentType.StripeIntent) {
_paymentService = new StripeIntent(_databaseService);
} else {
// Fallback
_paymentService = new StripeIntent(_databaseService);
}
// Add new payment plugins here
}
[Route("getcheckouttoken")]
[HttpPost]
public async Task<string> GetCheckoutToken() {
string OrderNumber = Guid.NewGuid().ToString().Substring(0, 10);
if (isLoggedIn()) {
Cart[] carts = await _databaseService.GetCart(getLoggedInUserID());
(bool, string) PaymentResponse = await _paymentService.TryGetCheckoutToken(OrderNumber, getLoggedInUserID(), carts);
if (PaymentResponse.Item1) {
// Returns client secret
return PaymentResponse.Item2;
} else {
Console.WriteLine("An error has occured in the payment plugin\n\n");
Console.WriteLine(PaymentResponse.Item2);
Console.WriteLine("\n");
return "An error has occured in the payment plugin";
}
}
return "You must be logged in";
}
[Route("getpublickey")]
[HttpPost]
public IActionResult GetPublicKey() {
try {
return Ok(IPayment._PublicKey);
} catch (Exception ex) {
return NotFound(ex.ToString());
}
}
[Route("response")]
[HttpPost]
public async Task<IActionResult> paymentWebhook() {
try {
string body = await new StreamReader(Request.Body).ReadToEndAsync();
await _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString());
return Ok();
} catch (Exception ex) {
return NotFound(ex.ToString());
}
}
}
}
@@ -0,0 +1,20 @@
using BoredCareers.Entities;
namespace BoredCareers.Controllers.Payment {
public interface IPayment {
public static PaymentType _PaymentType;
public static string _EndpointSecret = "";
public static string _PublicKey = "";
public Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, int userID, Cart[] cart);
public Task ValidatePurchase(string WebHookData, string Headers);
}
public enum PaymentType {
StripeIntent
}
}
@@ -0,0 +1,139 @@
using BoredCareers.Controllers.Payment;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
namespace BoredCareers.Controllers {
public class StripeIntent : IPayment {
DatabaseService _databaseService;
public StripeIntent(DatabaseService databaseService) {
_databaseService = databaseService;
}
public async Task<(bool, string)> TryGetCheckoutToken(string OrderNumber, int userID, Cart[] cart) {
try {
// build Recipt and calculate Tax
var options = new Stripe.Tax.CalculationCreateOptions {
Currency = "usd",
CustomerDetails = new Stripe.Tax.CalculationCustomerDetailsOptions {
AddressSource = "billing",
},
Expand = new List<string>() { "line_items" },
LineItems = new List<Stripe.Tax.CalculationLineItemOptions>()
};
List<int> prods = new List<int>();
// Add items to receipt
int subtotal = 0;
foreach (Cart items in cart) {
Product? product = await _databaseService.GetProduct(items.ProductID);
if (product != null) {
prods.Add(product.ID);
if (product != null) {
subtotal += product.Cost;
options.LineItems.Add(new Stripe.Tax.CalculationLineItemOptions {
Amount = product.Cost,
TaxCode = "txcd_10201000", // Tax code for downloadable digital games
Quantity = 1,
Reference = product.Name,
TaxBehavior = "exclusive"
});
}
}
}
var service = new Stripe.Tax.CalculationService();
Stripe.Tax.Calculation result = service.Create(options);
string csv = "";
foreach (int cur in prods) {
csv = csv + cur + ",";
}
// Crate Payment Intent
Stripe.PaymentIntentCreateOptions paymentIntent = new Stripe.PaymentIntentCreateOptions() {
Amount = result.AmountTotal,
Currency = "usd",
Metadata = new Dictionary<string, string> {
{ "ordernumber", OrderNumber },
{ "user", userID.ToString() },
{ "products", csv },
{ "subtotal", subtotal.ToString() },
{ "total", result.AmountTotal.ToString() }
},
StatementDescriptor = "Mistox.Net #" + OrderNumber
};
Stripe.PaymentIntentService intentService = new Stripe.PaymentIntentService();
Stripe.PaymentIntent x = await intentService.CreateAsync(paymentIntent);
return (true, x.ClientSecret);
} catch (Exception e) {
return (false, e.ToString());
}
}
public async Task ValidatePurchase(string WebHookData, string Headers) {
Stripe.Event e = Stripe.EventUtility.ConstructEvent( WebHookData, Headers, IPayment._EndpointSecret );
if (e.Type == "payment_intent.succeeded") {
// Extract Data from payment confirm
Stripe.PaymentIntent intent = (Stripe.PaymentIntent)e.Data.Object;
string orderNumber = "";
int userID = 0;
List<int> productIDs = new List<int>();
int subtotal = 0;
int total = 0;
KeyValuePair<string, string>[] y = intent.Metadata.ToArray();
foreach (KeyValuePair<string, string> cur in y) {
string val = cur.Key;
if (val == "ordernumber") {
orderNumber = cur.Value;
}
else if (val == "user") {
userID = int.Parse(cur.Value);
}
else if (val == "products") {
string[] products = cur.Value.Split(',');
foreach (string product in products) {
if (!string.IsNullOrEmpty(product)) {
productIDs.Add(Convert.ToInt32(product));
}
}
}
else if (val == "subtotal") {
subtotal = int.Parse(cur.Value);
}
else if (val == "total") {
total = int.Parse(cur.Value);
}
}
// Clear the cart
await _databaseService.ClearCart(userID);
// Add data to misox receipt
for (int i = 0; i < productIDs.Count; i++) {
int product = productIDs[i];
await _databaseService.NewReceipt(new Receipt {
AccountID = userID,
ProductID = product,
ReceiptID = orderNumber,
Time = DateTime.Now,
TaxAmount = total - subtotal,
TotalCost = total,
LineItem = i
});
}
} else {
Console.WriteLine("Unhandled event type: {0}", e.Type);
}
}
}
}
+143
View File
@@ -0,0 +1,143 @@
using Microsoft.AspNetCore.Mvc;
using BoredCareers.Services.DatabaseService;
using BoredCareers.Entities;
namespace BoredCareers.Controllers {
[ApiController]
[Route("api/product/[controller]")]
public class ProductController : MistoxControllerBase {
public ProductController(DatabaseService db) : base(db) { }
[Route("set")]
[HttpPost]
public async Task<ActionResult<bool>> CreateProduct([FromForm] Product obj, [FromForm] IFormFile[] images) {
try {
if (isLoggedIn()) {
Account user = await getLoggedInUser();
if (user.Role == "Admin") {
List<ProductImage> building = new List<ProductImage>();
foreach (var file in images) {
using (var stream = new MemoryStream()) {
await file.CopyToAsync(stream);
var bytes = stream.ToArray();
// Convert to your image model or whatever your logic is
ProductImage img = new ProductImage { Image = bytes, Name = file.FileName };
building.Add(img);
}
}
obj.Images = building.ToArray();
await _databaseService.SetProduct(obj);
return true;
}
}
return false;
} catch (Exception e) {
Console.WriteLine(e);
return false;
}
}
[Route("get")]
[HttpPost]
public async Task<ActionResult<Product>> GetProduct([FromForm] int productID) {
try {
Product? product = await _databaseService.GetProduct(productID);
if (product != null) {
return product;
}
else {
return NotFound();
}
} catch {
return NotFound();
}
}
[Route("getall")]
[HttpPost]
public async Task<Product[]> GetAllProducts() {
try {
return await _databaseService.GetAllProducts();
} catch {
return Array.Empty<Product>();
}
}
[Route("delete")]
[HttpPost]
public async Task<ActionResult<bool>> DeleteProduct([FromForm] int productID) {
try {
if (isLoggedIn()) {
Account user = await getLoggedInUser();
if (user.Role == "Admin") {
await _databaseService.DeleteProduct(productID);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("getimage")]
[HttpPost]
public async Task<IActionResult> GetProductImage([FromForm] int ProductID, [FromForm] int ImageID) {
try {
ProductImage? img = await _databaseService.GetImage(ProductID, ImageID);
if (img != null) {
return File(img.Image, "Image/*");
}
else {
return NotFound();
}
} catch {
return NotFound();
}
}
[Route("getowned")]
[HttpPost]
public async Task<ActionResult<Receipt[]>> GetOwnedProduct() {
try {
if (isLoggedIn()) {
Receipt[] returned = await _databaseService.GetAllReceipts(getLoggedInUserID());
return returned;
}
return new Receipt[0];
} catch {
return new Receipt[0];
}
}
[Route("download")]
[HttpGet]
public async Task<ActionResult> Download([FromQuery] string Product) {
try {
if (isLoggedIn()) {
Product[] games = await _databaseService.GetAllProducts();
foreach (Product product in games) {
if (contains(Product, product.URL)) {
Receipt? receipt = await _databaseService.GetReceipt(getLoggedInUserID(), product.ID);
if (receipt != null) {
//FileStream fileStream = new FileStream(_FolderRoot + Product, FileMode.Open, FileAccess.Read);
//return new FileStreamResult( fileStream, "application/octet-stream" ) {
// FileDownloadName = fileStream.Name
//};
}
break;
}
}
return Unauthorized();
}
return Unauthorized();
} catch {
return NotFound();
}
}
}
}
+59
View File
@@ -0,0 +1,59 @@
// Reflections of SQL Database objects
namespace BoredCareers.Entities {
public class Account {
public int ID { get; set; } // PK
public string UserName { get; set; } = "";
public string Email { get; set; } = "";
public bool EmailVerified { get; set; } = false;
public string PasswordHash { get; set; } = "";
public bool FailedPasswordLock { get; set; } = false;
public int PasswordAttempts { get; set; } = 5;
public int CurrentPasswordAttempts { get; set; } = 0;
public string Role { get; set; } = "Generic";
public string EmailToken { get; set; } = "";
public string Error { get; set; } = "";
}
public class Product {
public int ID { get; set; } // PK
public string Name { get; set; } = "";
public string Description { get; set; } = "";
public ProductImage[] Images { get; set; } = [];
public int Cost { get; set; }
public string URL { get; set; } = "";
}
public class ProductImage {
public int ImageID { get; set; } // PK
public int ProductID { get; set; } // PK
public byte[] Image { get; set; } = Array.Empty<byte>();
public string Name { get; set; } = "";
}
public class ProductInventory {
public int AccountID { get; set; } // PK
public int ProductID { get; set; } // PK
public string Key { get; set; } = string.Empty; // PK
public string Value { get; set; } = string.Empty;
}
public class Cart {
public int ID { get; set; } // PK
public int AccountID { get; set; }
public int ProductID { get; set; }
}
public class Receipt {
public int AccountID { get; set; } // PK
public int ProductID { get; set; } // PK
public string ReceiptID { get; set; } = string.Empty; // PK
public int LineItem { get; set; }
public DateTime Time { get; set; }
public int TaxAmount { get; set; }
public int TotalCost { get; set; }
}
}
+120
View File
@@ -0,0 +1,120 @@
using Microsoft.AspNetCore.Authentication.Cookies;
using BoredCareers.Controllers.Payment;
using BoredCareers.Services;
using BoredCareers.Services.DatabaseService;
using Stripe;
var builder = WebApplication.CreateBuilder(args);
// Disable null warnings becuse string.IsNullOrEmpty checks for NULL or Empty
#pragma warning disable CS8600
#pragma warning disable CS8604
////////////////////////////////
/////// Database Service ///////
////////////////////////////////
// Address
string? _dbserver = Environment.GetEnvironmentVariable("MySQLServer");
string dbserver = !string.IsNullOrEmpty(_dbserver) ? _dbserver : "localhost";
// Database
string? _dbdatabase = Environment.GetEnvironmentVariable("MySQLDatabase");
string dbdatabase = !string.IsNullOrEmpty(_dbdatabase) ? _dbdatabase : "mistox";
// UserName
string? _dbuser = Environment.GetEnvironmentVariable("MySQLUser");
string dbUser = !string.IsNullOrEmpty(_dbuser) ? _dbuser : "root";
// Password
string? _dbpass = Environment.GetEnvironmentVariable("MySQLPass");
string dbPass = !string.IsNullOrEmpty(_dbpass) ? _dbpass : "oasv34$8gpv023dd";
// Create the database serivice
DatabaseService databaseService = new DatabaseService(connectionString: "server=" + dbserver + ";user=" + dbUser + ";database=" + dbdatabase + ";password=" + dbPass + ";port=3306;");
builder.Services.Add( new ServiceDescriptor( typeof( DatabaseService ), databaseService ) );
////////////////////////////////
///////// Email Service ////////
////////////////////////////////
// Address
string? _eServer = Environment.GetEnvironmentVariable("EmailServer");
string EmailServer = !string.IsNullOrEmpty(_eServer) ? _eServer : "mail.mistox.com";
// Port
string? _ePort = Environment.GetEnvironmentVariable("EmailPort");
int EmailPort = !string.IsNullOrEmpty(_ePort) ? Convert.ToInt32(_ePort) : 587;
// User
string? _eAddress = Environment.GetEnvironmentVariable("EmailAddress");
string EmailAddress = !string.IsNullOrEmpty(_eAddress) ? _eAddress : "no-reply@mistox.com";
// Password
string? _ePassword = Environment.GetEnvironmentVariable("EmailPassword");
string EmailPassword = !string.IsNullOrEmpty(_ePassword) ? _ePassword : "";
// Create the email service
EmailService Emailservice = new EmailService( EmailServer, EmailPort, EmailAddress, EmailPassword );
builder.Services.Add( new ServiceDescriptor( typeof( EmailService ), Emailservice ));
////////////////////////////////
/////// Payment Service ////////
////////////////////////////////
// Payment service name -> must be name of PaymentType enum
string? PaymentService = Environment.GetEnvironmentVariable("PaymentService");
IPayment._PaymentType = (PaymentType)Enum.Parse(typeof(PaymentType), PaymentService, true);
if (IPayment._PaymentType == PaymentType.StripeIntent) {
// Get PublicKey
string? StripePublicKey = Environment.GetEnvironmentVariable("StripePublicKey");
IPayment._PublicKey = string.IsNullOrEmpty(StripePublicKey) ? "" : StripePublicKey;
// Get PrivateKey
string? StripeAPIKey = Environment.GetEnvironmentVariable("StripeApiKey");
StripeConfiguration.ApiKey = StripeAPIKey;
// Get Endpoint secret
string? StripeEndpointKey = Environment.GetEnvironmentVariable("StripeEndpointSecret");
IPayment._EndpointSecret = string.IsNullOrEmpty(StripeEndpointKey) ? "" : StripeEndpointKey;
}
// Authentication Service
builder.Services.AddAuthentication( options => {
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
} ).AddCookie(options => {
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.LoginPath = "/account/login";
options.LogoutPath = "/account/logout";
options.SlidingExpiration = true;
});
builder.Services.AddCors( o => o.AddDefaultPolicy( builder => {
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); // No CORS
} ) );
// Pages Service
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if( !app.Environment.IsDevelopment() ) {
app.UseHsts();
}
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseCors();
app.UseRouting();
app.UseAuthentication();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
+27
View File
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.3.0" />
<PackageReference Include="MySql.Data" Version="9.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Stripe.net" Version="48.2.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
<ItemGroup>
<Content Update="wwwroot\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
+160
View File
@@ -0,0 +1,160 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<Account?> GetAccount( string UserNameOrEmail ) {
Account? account = null;
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT *
FROM Account
WHERE UserName = @UorE OR Email = @UorE;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@UorE", UserNameOrEmail);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _id = reader.GetInt32("ID");
string _username = reader.GetString("UserName");
string _email = reader.GetString("Email");
bool _emailVerified = reader.GetBoolean("EmailVerified");
string _passwordhash = reader.GetString("PasswordHash");
bool _failedpasswordlock = reader.GetBoolean( "FailedPasswordLock" );
int _passwordattempts = reader.GetInt32( "PasswordAttempts" );
int _curpasswordattempts = reader.GetInt32( "CurrentPasswordAttempts" );
string _role = reader.GetString( "Role" );
string _emailtoken = reader.GetString( "EmailToken" );
account = new Account() {
ID = _id,
UserName = _username,
Email = _email,
EmailVerified = _emailVerified,
PasswordHash = _passwordhash,
CurrentPasswordAttempts = _curpasswordattempts,
PasswordAttempts = _passwordattempts,
EmailToken = _emailtoken,
FailedPasswordLock = _failedpasswordlock,
Role = _role,
};
}
}
}
return account;
}
public async Task<Account?> GetAccount( int ID ) {
Account? account = null;
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT *
FROM Account
WHERE ID = @ID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ID", ID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _id = reader.GetInt32("ID");
string _username = reader.GetString("UserName");
string _email = reader.GetString("Email");
bool _emailVerified = reader.GetBoolean("EmailVerified");
string _passwordhash = reader.GetString("PasswordHash");
bool _failedpasswordlock = reader.GetBoolean( "FailedPasswordLock" );
int _passwordattempts = reader.GetInt32( "PasswordAttempts" );
int _curpasswordattempts = reader.GetInt32( "CurrentPasswordAttempts" );
string _role = reader.GetString( "Role" );
string _emailtoken = reader.GetString( "EmailToken" );
account = new Account() {
ID = _id,
UserName = _username,
Email = _email,
EmailVerified = _emailVerified,
PasswordHash = _passwordhash,
CurrentPasswordAttempts = _passwordattempts,
PasswordAttempts = _passwordattempts,
EmailToken = _emailtoken,
FailedPasswordLock = _failedpasswordlock,
Role = _role,
};
}
}
}
return account;
}
public async Task SetAccount( Account Profile ) {
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
INSERT INTO Account
(ID,UserName,Email,EmailVerified,PasswordHash,FailedPasswordLock,PasswordAttempts,CurrentPasswordAttempts,Role,EmailToken)
VALUES
(@ID,@UserName,@Email,@EmailVerified,@PasswordHash,@FailedPasswordLock,@PasswordAttempts,@CurrentPasswordAttempts,@Role,@EmailToken);
ON DUPLICATE KEY UPDATE
UserName = @UserName,
Email = @Email,
EmailVerified = @EmailVerified,
PasswordHash = @PasswordHash,
FailedPasswordLock = @FailedPasswordLock,
PasswordAttempts = @PasswordAttempts,
CurrentPasswordAttempts = @CurrentPasswordAttempts,
Role = @Role,
EmailToken = @EmailToken;
";
MySqlCommand cmd = new MySqlCommand( command , connection);
cmd.Parameters.AddWithValue("@ID", Profile.ID);
cmd.Parameters.AddWithValue("@UserName", Profile.UserName);
cmd.Parameters.AddWithValue("@Email", Profile.Email);
cmd.Parameters.AddWithValue("@EmailVerified", Profile.EmailVerified);
cmd.Parameters.AddWithValue("@PasswordHash", Profile.PasswordHash);
cmd.Parameters.AddWithValue("@FailedPasswordLock", Profile.FailedPasswordLock);
cmd.Parameters.AddWithValue("@PasswordAttempts", Profile.PasswordAttempts);
cmd.Parameters.AddWithValue("@CurrentPasswordAttempts", Profile.CurrentPasswordAttempts);
cmd.Parameters.AddWithValue("@Role", Profile.Role);
cmd.Parameters.AddWithValue("@EmailToken", Profile.EmailToken);
await cmd.ExecuteNonQueryAsync();
}
}
public async Task DeleteAccount( int ID ) {
using( MySqlConnection connection = GetConnection() ) {
MySqlCommand cmd;
connection.Open();
string command = @"
DELETE FROM Account WHERE ID = @ID;
DELETE FROM AccountInventory WHERE AccountID = @ID;
DELETE FROM ProjectMistData WHERE AccountID = @ID;
DELETE FROM Cart WHERE AccountID = @ID;
";
cmd = new MySqlCommand( command, connection );
cmd.Parameters.AddWithValue("@ID", ID);
await cmd.ExecuteNonQueryAsync();
}
}
}
}
+82
View File
@@ -0,0 +1,82 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<Cart[]> GetCart( int accountID ) {
List<Cart> list = new List<Cart>();
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROM Cart
WHERE AccountID = @AccountID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _id = reader.GetInt32("ID");
int _accountid = reader.GetInt32("AccountID");
int _productid = reader.GetInt32("ProductID");
list.Add( new Cart() {
ID = _id,
AccountID = _accountid,
ProductID = _productid
} );
}
}
}
return list.ToArray();
}
public async Task AddToCart( Cart item ) {
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
INSERT INTO Cart
(AccountID, ProductID)
VALUES
(@AccountID, @ProductID);
";
MySqlCommand cmd = new MySqlCommand( command , connection);
cmd.Parameters.AddWithValue("@AccountID", item.AccountID);
cmd.Parameters.AddWithValue("@ProductID", item.ProductID);
await cmd.ExecuteNonQueryAsync();
}
}
public async Task RemoveFromCart( Cart item ) {
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = "DELETE FROM Cart WHERE AccountID=" + item.AccountID + " AND ProductID=" + item.ProductID + ";";
MySqlCommand cmd = new MySqlCommand( command , connection);
await cmd.ExecuteNonQueryAsync();
}
}
public async Task ClearCart( int accountID ) {
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
DELETE FROM Cart
WHERE AccountID = @AccountID;
";
MySqlCommand cmd = new MySqlCommand( command , connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
await cmd.ExecuteNonQueryAsync();
}
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using MySql.Data.MySqlClient;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public string ConnectionString {
get; set;
}
public DatabaseService( string connectionString ) {
ConnectionString = connectionString;
}
MySqlConnection GetConnection() {
return new MySqlConnection( ConnectionString );
}
}
}
+136
View File
@@ -0,0 +1,136 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<Product?> GetProduct(int ID) {
Product? items = null;
using (MySqlConnection connection = GetConnection()) {
connection.Open();
string command = @"
SELECT * FROM Product
WHERE ID = @ID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ID", ID);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
int _id = reader.GetInt32("ID");
string _name = reader.GetString("Name");
string _description = reader.GetString("Description");
int _cost = reader.GetInt32("Cost");
string _url = reader.GetString("URL");
ProductImage[] images = await GetAllImages(_id);
items = new Product() {
ID = _id,
Name = _name,
Images = images,
Description = _description,
Cost = _cost,
URL = _url
};
}
}
}
return items;
}
public async Task<Product[]> GetAllProducts() {
List<Product> items = new List<Product>();
using (MySqlConnection connection = GetConnection()) {
connection.Open();
MySqlCommand cmd = new MySqlCommand("SELECT * FROM Product", connection);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
int _id = reader.GetInt32("ID");
string _name = reader.GetString("Name");
string _description = reader.GetString("Description");
int _cost = reader.GetInt32("Cost");
string _url = reader.GetString("URL");
ProductImage[] images = await GetAllImages(_id);
items.Add(new Product() {
ID = _id,
Name = _name,
Images = images,
Description = _description,
Cost = _cost,
URL = _url
});
}
}
}
return items.ToArray();
}
public async Task SetProduct(Product Item) {
using (MySqlConnection connection = GetConnection()) {
connection.Open();
string command = @"
INSERT INTO Product
(ID,Name,Description,Cost,URL)
VALUES
(@ID,@Name,@Description,@Cost,@URL)
ON DUPLICATE KEY UPDATE
Name = @Name,
Description = @Description,
Cost = @Cost,
URL = @URL
WHERE ID = @ID;
SELECT ID FROM Product
WHERE Name = @Name;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ID", Item.ID);
cmd.Parameters.AddWithValue("@Name", Item.Name);
cmd.Parameters.AddWithValue("@Description", Item.Description);
cmd.Parameters.AddWithValue("@Cost", Item.Cost);
cmd.Parameters.AddWithValue("@URL", Item.URL);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
Item.ID = reader.GetInt32("ID");
}
}
await AddAllImages(Item);
}
}
public async Task DeleteProduct(int ID) {
using (MySqlConnection connection = GetConnection()) {
await DeleteAllImages(ID);
connection.Open();
string command = @"
DELETE FROM Product
WHERE ID = @ID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ID", ID);
await cmd.ExecuteNonQueryAsync();
}
}
}
}
@@ -0,0 +1,112 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<ProductImage?> GetImage(int ProductID, int ImageID) {
ProductImage? item = null;
using (MySqlConnection connection = GetConnection()) {
connection.Open();
string command = @"
SELECT * FROM ProductImage
WHERE ProductID = @ProductID AND ImageID = @ImageID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ProductID", ProductID);
cmd.Parameters.AddWithValue("@ImageID", ImageID);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
int _ImageID = reader.GetInt32("ImageID");
int _ProductID = reader.GetInt32("ProductID");
byte[] _Image = (byte[])reader["Image"];
string _Name = reader.GetString("Name");
item = new ProductImage() {
ImageID = _ImageID,
ProductID = _ProductID,
Image = _Image,
Name = _Name
};
break;
}
}
}
return item;
}
public async Task<ProductImage[]> GetAllImages(int ProductID) {
List<ProductImage> items = new List<ProductImage>();
using (MySqlConnection connection = GetConnection()) {
connection.Open();
string command = @"
SELECT * FROM ProductImage
WHERE ProductID = @ProductID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ProductID", ProductID);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
int _ImageID = reader.GetInt32("ImageID");
int _ProductID = reader.GetInt32("ProductID");
string _Name = reader.GetString("Name");
items.Add(new ProductImage() {
ImageID = _ImageID,
ProductID = _ProductID,
Name = _Name
});
}
}
}
return items.ToArray();
}
public async Task AddAllImages(Product Item) {
using (MySqlConnection connection = GetConnection()) {
connection.Open();
foreach (ProductImage cur in Item.Images) {
if (cur.Image != null) {
string command = @"
INSERT INTO ProductImage
(ProductID, Image, Name)
VALUES
(@ProductID, @Image, @Name);
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ProductID", Item.ID);
cmd.Parameters.AddWithValue("@Image", cur.Image );
cmd.Parameters.AddWithValue("@Name", cur.Name );
await cmd.ExecuteNonQueryAsync();
}
}
}
}
public async Task DeleteAllImages(int ItemID) {
using (MySqlConnection connection = GetConnection()) {
connection.Open();
string command = @"
DELETE FROM ProductImage
WHERE ProductID = @ProductID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@ProductID", ItemID);
await cmd.ExecuteNonQueryAsync();
}
}
}
}
+100
View File
@@ -0,0 +1,100 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<ProductInventory[]> GetAllProductInventory( int accountID, int productID ) {
List<ProductInventory> list = new List<ProductInventory>();
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROM ProductInventory
WHERE AccountID = @AccountID AND ProductID = @ProductID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
cmd.Parameters.AddWithValue("@ProductID", productID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
string _Key = reader.GetString("Key");
string _Value = reader.GetString("Value");
list.Add( new ProductInventory() {
AccountID = accountID,
ProductID = productID,
Key = _Key,
Value = _Value
} );
}
}
}
return list.ToArray();
}
public async Task<ProductInventory> GetProductInventory( int accountID, int productID, string Key ) {
ProductInventory item = new ProductInventory();
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROM ProductInventory
WHERE AccountID = @AccountID AND ProductID = @ProductID AND Key = @Key;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
cmd.Parameters.AddWithValue("@ProductID", productID);
cmd.Parameters.AddWithValue("@Key", Key);
using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
while (await reader.ReadAsync()) {
if (reader == null) {
break;
}
string _Key = reader.GetString("Key");
string _Value = reader.GetString("Value");
item = new ProductInventory() {
AccountID = accountID,
ProductID = productID,
Key = _Key,
Value = _Value
};
}
}
}
return item;
}
async Task SetProductInventory(ProductInventory item) {
using (MySqlConnection connection = GetConnection()) {
string command = @"
INSERT INTO ProductInventory
(AccountID, ProductID, `Key`, `Value`)
Values
(@AccountID, @ProductID, @Key, @Value)
ON DUPLICATE KEY UPDATE
`Value` = @Value;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", item.AccountID);
cmd.Parameters.AddWithValue("@ProductID", item.ProductID);
cmd.Parameters.AddWithValue("@Key", item.Key);
cmd.Parameters.AddWithValue("@Value", item.Value ?? (object)DBNull.Value);
await cmd.ExecuteNonQueryAsync();
}
}
}
}
+171
View File
@@ -0,0 +1,171 @@
using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;
namespace BoredCareers.Services.DatabaseService {
public partial class DatabaseService {
public async Task<Receipt[]> GetAllReceipts( int accountID ) {
List<Receipt> receipts = new List<Receipt> ();
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROM Receipt
WHERE AccountID = @AccountID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _accountid = reader.GetInt32("AccountID");
int _gameid = reader.GetInt32("ProductID");
string _receiptid = reader.GetString("ReceiptID");
int _lineitem = reader.GetInt32("LineItem");
DateTime _receiptdate = reader.GetDateTime("Time");
int _taxamount = reader.GetInt32("TaxAmount");
int _totalcost = reader.GetInt32("TotalCost");
receipts.Add( new Receipt() {
AccountID = _accountid,
ProductID = _gameid,
ReceiptID = _receiptid,
Time = _receiptdate,
TotalCost = _totalcost,
TaxAmount = _taxamount,
LineItem = _lineitem
} );
}
}
}
return receipts.ToArray();
}
public async Task<( Receipt, Product )[]> GetAllReceiptsJoinedToProduct( int accountID ) {
List<( Receipt, Product )> join = new();
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROM Receipt
LEFT JOIN Product
ON Receipt.ProductID = Product.ID
WHERE AccountID = @AccountID
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _accountid = !reader.IsDBNull( "AccountID" ) ? reader.GetInt32("AccountID") : -1;
int _gameid = !reader.IsDBNull( "ProductID" ) ? reader.GetInt32("ProductID") : 0;
string _receiptid = !reader.IsDBNull( "ReceiptID" ) ? reader.GetString("ReceiptID") : "";
int _lineitem = !reader.IsDBNull( "LineItem" ) ? reader.GetInt32("LineItem") : 0;
DateTime _receiptdate = !reader.IsDBNull( "Time" ) ? reader.GetDateTime("Time") : DateTime.Now;
int _taxamount = !reader.IsDBNull( "TaxAmount" ) ? reader.GetInt32("TaxAmount") : 0;
int _totalcost = !reader.IsDBNull( "TotalCost" ) ? reader.GetInt32("TotalCost") : 0;
int _id = !reader.IsDBNull( "ID" ) ? reader.GetInt32("ID") : 0;
string _name = !reader.IsDBNull( "Name" ) ? reader.GetString("Name") : "";
string _desc = !reader.IsDBNull( "Description" ) ? reader.GetString("Description") : "";
int _cost = !reader.IsDBNull( "Cost" ) ? reader.GetInt32("Cost") : 0;
string _url = !reader.IsDBNull( "URL" ) ? reader.GetString("URL") : "Something Random That Wont Ever Be In A URL";
Receipt r = new() {
AccountID = _accountid,
ProductID = _gameid,
ReceiptID = _receiptid,
Time = _receiptdate,
TotalCost = _totalcost,
TaxAmount = _taxamount,
LineItem = _lineitem
};
Product p = new() {
ID = _id,
Cost = _cost,
Description = _desc,
Name = _name,
URL = _url
};
join.Add( (r, p) );
}
}
}
return join.ToArray();
}
public async Task<Receipt?> GetReceipt( int accountID, int gameID ) {
Receipt? receipt = null;
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
SELECT * FROMReceipt
WHERE AccountID = @AccountID AND ProductID = @ProductID;
";
MySqlCommand cmd = new MySqlCommand(command, connection);
cmd.Parameters.AddWithValue("@AccountID", accountID);
cmd.Parameters.AddWithValue("@ProductID", gameID);
using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) {
while( await reader.ReadAsync() ) {
if( reader == null ) {
break;
}
int _accountid = reader.GetInt32("AccountID");
int _gameid = reader.GetInt32("ProductID");
string _receiptid = reader.GetString("ReceiptID");
int _lineitem = reader.GetInt32("LineItem");
DateTime _receiptdate = reader.GetDateTime("Time");
int _taxamount = reader.GetInt32("TaxAmount");
int _totalcost = reader.GetInt32("TotalCost");
receipt = new Receipt() {
AccountID = _accountid,
ProductID = _gameid,
ReceiptID = _receiptid,
Time = _receiptdate,
TotalCost = _totalcost,
TaxAmount = _taxamount,
LineItem = _lineitem
};
}
}
}
return receipt;
}
public async Task NewReceipt( Receipt receipt ) {
using( MySqlConnection connection = GetConnection() ) {
connection.Open();
string command = @"
INSERT INTO Receipt
(AccountID, ProductID, ReceiptID, LineItem, TaxAmount, TotalCost, Time)
VALUES
(@AccountID, @ProductID, @ReceiptID, @LineItem, @TaxAmount, @TotalCost, @Time)
";
MySqlCommand cmd = new MySqlCommand( command , connection);
cmd.Parameters.AddWithValue("@AccountID", receipt.AccountID);
cmd.Parameters.AddWithValue("@ProductID", receipt.ProductID);
cmd.Parameters.AddWithValue("@ReceiptID", receipt.ReceiptID);
cmd.Parameters.AddWithValue("@LineItem", receipt.LineItem);
cmd.Parameters.AddWithValue("@TaxAmount", receipt.TaxAmount);
cmd.Parameters.AddWithValue("@TotalCost", receipt.TotalCost);
cmd.Parameters.AddWithValue("@Time", receipt.Time); // Just incase i need this in the future | receipt.Time.ToString( "yyyy-MM-dd hh:mm:ss" )
await cmd.ExecuteNonQueryAsync();
}
}
}
}
+41
View File
@@ -0,0 +1,41 @@
using System.Net.Mail;
namespace BoredCareers.Services {
public partial class EmailService {
public Dictionary<string, DateTime> _SentEmails = new Dictionary<string, DateTime>();
public string EmailServer = "";
public string EmailAddress = "";
public string EmailPassword = "";
public int EmailPort;
public EmailService( string _EmailServer, int _EmailPort, string _EmailAddress, string _EmailPassword ) {
EmailServer = _EmailServer;
EmailPort = _EmailPort;
EmailAddress = _EmailAddress;
EmailPassword = _EmailPassword;
}
public string Send( string Destination, string Subject, string Body ) {
using (SmtpClient client = new SmtpClient( EmailServer, EmailPort )){
client.EnableSsl = true;
client.Credentials = new System.Net.NetworkCredential( EmailAddress, EmailPassword );
try {
MailMessage msg = new MailMessage(){
IsBodyHtml = true,
Subject = Subject,
Body = Body
};
msg.From = new MailAddress( EmailAddress, "no-reply" );
msg.To.Add( new MailAddress( Destination ) );
client.Send( msg );
return "Success";
} catch( Exception e ) {
return "An Error Has Occurred Sending Email : " + e.ToString();
}
}
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System.Net.Mail;
namespace BoredCareers.Services {
public partial class EmailService {
// @UserName
// @ResetPassWord
// https://mistox.com/account/resetpassword?UserName=@UserName&ResetPwd=@ResetPassWord
public static string ResetPasswordSubject = "Password Reset Request";
public static string ResetPasswordEmail = @"
<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""UTF-8"">
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
<title>Password Reset</title>
</head>
<body style=""font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 0;"">
<table role=""presentation"" style=""width: 100%; background-color: #f4f4f4; padding: 20px 0;"">
<tr>
<td>
<table role=""presentation"" style=""max-width: 600px; width: 100%; background-color: #ffffff; margin: 0 auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"">
<tr>
<td style=""padding: 20px; text-align: center; background-color: #4CAF50; color: #ffffff; border-top-left-radius: 8px; border-top-right-radius: 8px;"">
<h2>Password Reset Request</h2>
</td>
</tr>
<tr>
<td style=""padding: 20px; text-align: left; font-size: 16px; color: #333333;"">
<p>Hi @UserName,</p>
<p>We received a request to reset your password. You can reset your password by clicking the button below:</p>
<p style=""text-align: center;"">
<a href=""https://mistox.com/account/resetpassword?UserName=@UserName&ResetPwd=@ResetPassWord"" style=""background-color: #4CAF50; color: #ffffff; text-decoration: none; padding: 15px 25px; font-size: 16px; border-radius: 5px; display: inline-block;"">Reset Password</a>
</p>
<p>If you didn't request a password reset, you can safely ignore this email.</p>
<p>Best regards</p>
</td>
</tr>
<tr>
<td style=""padding: 10px; text-align: center; background-color: #f4f4f4; color: #888888; font-size: 12px; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;"">
<p>If you have any questions, feel free to <a href=""mailto:webmaster@mistox.com"" style=""color: #4CAF50; text-decoration: none;"">contact support</a>.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
";
}
}
+54
View File
@@ -0,0 +1,54 @@
using System.Net.Mail;
namespace BoredCareers.Services {
public partial class EmailService {
// @UserName
// @VerifyPassword
// https://mistox.com/api/account/verifyemail?UserName=@UserName&Guid=@VerifyPassword
public static string VerifyEmailSubject = "Verify Your Email Address";
public static string VerifyEmailEmail = @"
<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""UTF-8"">
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
<title>Verify Your Email</title>
</head>
<body style=""font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 0;"">
<table role=""presentation"" style=""width: 100%; background-color: #f4f4f4; padding: 20px 0;"">
<tr>
<td>
<table role=""presentation"" style=""max-width: 600px; width: 100%; background-color: #ffffff; margin: 0 auto; border-radius: 8px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);"">
<tr>
<td style=""padding: 20px; text-align: center; background-color: #4CAF50; color: #ffffff; border-top-left-radius: 8px; border-top-right-radius: 8px;"">
<h2>Verify Email Request</h2>
</td>
</tr>
<tr>
<td style=""padding: 20px; text-align: left; font-size: 16px; color: #333333;"">
<p>Hi @UserName,</p>
<p>Thank you for making an account with us:</p>
<p>In order to start using your account we need to verify your email address by clicking the link below:</p>
<p style=""text-align: center;"">
<a href=""https://mistox.com/account/verifyemail?UserName=@UserName&Guid=@VerifyPassword"" style=""background-color: #4CAF50; color: #ffffff; text-decoration: none; padding: 15px 25px; font-size: 16px; border-radius: 5px; display: inline-block;"">Verify Email</a>
</p>
<p>If you didn't create an account please ignore this email.</p>
<p>Best regards</p>
</td>
</tr>
<tr>
<td style=""padding: 10px; text-align: center; background-color: #f4f4f4; color: #888888; font-size: 12px; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;"">
<p>If you have any questions, feel free to <a href=""mailto:webmaster@mistox.com"" style=""color: #4CAF50; text-decoration: none;"">contact support</a>.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
";
}
}
+33
View File
@@ -0,0 +1,33 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", ".\Server.csproj", "{76F2B6C1-FF9A-4BD8-AB7A-7456E8122C44}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9E4D64F9-2F56-4AC5-85CE-51EFEE1513C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E4D64F9-2F56-4AC5-85CE-51EFEE1513C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E4D64F9-2F56-4AC5-85CE-51EFEE1513C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E4D64F9-2F56-4AC5-85CE-51EFEE1513C0}.Release|Any CPU.Build.0 = Release|Any CPU
{76F2B6C1-FF9A-4BD8-AB7A-7456E8122C44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76F2B6C1-FF9A-4BD8-AB7A-7456E8122C44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76F2B6C1-FF9A-4BD8-AB7A-7456E8122C44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76F2B6C1-FF9A-4BD8-AB7A-7456E8122C44}.Release|Any CPU.Build.0 = Release|Any CPU
{19C67017-8C26-439B-95B3-FE346D1AC7D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19C67017-8C26-439B-95B3-FE346D1AC7D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19C67017-8C26-439B-95B3-FE346D1AC7D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19C67017-8C26-439B-95B3-FE346D1AC7D5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B413876B-4048-47F1-B8B8-B974DF5E9E2A}
EndGlobalSection
EndGlobal
+179
View File
@@ -0,0 +1,179 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Stripe-Payments</title>
<script src="https://js.stripe.com/v3/"></script>
<style>
#submit {
width: 200px;
height: 40px;
margin-left: calc(50% - 100px);
margin-top: 30px;
color: #fff;
background-color: #393;
font-size: 16px;
text-decoration: none;
text-transform: uppercase;
overflow: hidden;
transition: .5s;
letter-spacing: 4px;
border: 1px solid #8F7CEC;
}
#submit:hover {
background: #353;
color: #fff;
border-radius: 5px;
border-color: #353;
}
</style>
</head>
<body>
<form id="payment-form">
<div id="link-authentication-element">
<!--Stripe.js injects the Link Authentication Element-->
</div>
<div id="payment-element">
<!--Stripe.js injects the Payment Element-->
</div>
<button id="submit">
<div class="spinner hidden" id="spinner"></div>
<span id="button-text">Pay now</span>
</button>
<div id="payment-message" class="hidden"></div>
</form>
<script>
// This is your test publishable API key.
const stripe = Stripe('pk_live_51LBODxCozZzTNCNhFdVbzm93F1N3Kk5sEiOyUYeU8GlqxF8AkS6h1JOkIqmFJ1hBmkBCEEa8cfBCY7RotHlweS7g00UzyxkUnO');
let elements;
initialize();
checkStatus();
document.querySelector("#payment-form").addEventListener("submit", handleSubmit);
let emailAddress = '';
// Fetches a payment intent and captures the client secret
async function initialize() {
const response = await fetch("/api/getCheckoutToken?userID=" + new URL(window.location.href).searchParams.get("userID"), {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: ""
});
const clientSecret = await response.text();
const appearance = {
theme: 'night',
};
elements = stripe.elements({ appearance, clientSecret });
const linkAuthenticationElement = elements.create("linkAuthentication");
linkAuthenticationElement.mount("#link-authentication-element");
linkAuthenticationElement.on('change', (event) => {
emailAddress = event.value.email;
});
const paymentElementOptions = {
layout: "tabs",
};
const paymentElement = elements.create("payment", paymentElementOptions);
paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
// Make sure to change this to your payment completion page
return_url: "https://mistox.net/store/payment/success",
receipt_email: emailAddress,
},
});
// This point will only be reached if there is an immediate error when
// confirming the payment. Otherwise, your customer will be redirected to
// your `return_url`. For some payment methods like iDEAL, your customer will
// be redirected to an intermediate site first to authorize the payment, then
// redirected to the `return_url`.
if (error.type === "card_error" || error.type === "validation_error") {
showMessage(error.message);
} else {
showMessage("An unexpected error occurred.");
}
setLoading(false);
}
// Fetches the payment intent status after payment submission
async function checkStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
switch (paymentIntent.status) {
case "succeeded":
showMessage("Payment succeeded!");
break;
case "processing":
showMessage("Your payment is processing.");
break;
case "requires_payment_method":
showMessage("Your payment was not successful, please try again.");
break;
default:
showMessage("Something went wrong.");
break;
}
}
// ------- UI helpers -------
function showMessage(messageText) {
const messageContainer = document.querySelector("#payment-message");
messageContainer.classList.remove("hidden");
messageContainer.textContent = messageText;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageText.textContent = "";
}, 4000);
}
// Show a spinner on payment submission
function setLoading(isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.querySelector("#submit").disabled = true;
document.querySelector("#spinner").classList.remove("hidden");
document.querySelector("#button-text").classList.add("hidden");
} else {
document.querySelector("#submit").disabled = false;
document.querySelector("#spinner").classList.add("hidden");
document.querySelector("#button-text").classList.remove("hidden");
}
}
</script>
</body>
</html>
+192
View File
@@ -0,0 +1,192 @@
<html>
<head>
<title>HTML_Snake</title>
</head>
<body onkeydown='return keyDown(event)'; style="background-color: #333;">
<h1 id="Score" style="width: 100%; text-align: center; color:#fff;">Score : 0</h1>
<div id="BODY" style="position: relative; margin-bottom: 5px; margin-left: 50%; right: 300px; background-color: #666; width: 600px; height: 600px;">
<script>
var snake = [];
var score = 0;
var posX = 12;
var posY = 15;
var colX, colY;
var saves = "";
var paused = false;
var direction = 2;
var wasCollected = false;
var body = document.getElementById("BODY");
function set(name,value) {
var expires = "";
var date = new Date();
date.setTime(date.getTime() + (9999*24*60*60*1000));
expires = "; expires=" + date.toUTCString();
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function get(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function hsl2rgb(h,s,l) {
let a=s*Math.min(l,1-l);
let f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1);
return [f(0),f(8),f(4)];
}
var degree = 0;
function newTail(x, y){
degree += 5;
if(degree > 359){
degree = 0;
}
var color = hsl2rgb(degree, .6, .5);
var r = Math.floor(color[0] * 255).toString(16);
var g = Math.floor(color[1] * 255).toString(16);
var b = Math.floor(color[2] * 255).toString(16);
var nX = (10*x)-10;
var nY = (10*y)-10;
var id = x + "," + y;
if (x == colX){
if (y == colY){
var item = document.getElementById("collectable");
item.parentNode.removeChild(item);
wasCollected = true;
newCollectable();
score += 1;
document.getElementById("Score").innerHTML = "Score : " + score;
}
}
body.innerHTML = body.innerHTML + "<div id='" + id + "'; style='position: absolute; left: " + nX + "px; top:" + nY + "px; width: 10px; height: 10px; background-color: #" + r+g+b + "; border: 0; padding: 0; margin: 0;'></div>";
return id;
}
function randInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function newCollectable(){
colX = randInt(1, 59);
colY = randInt(1, 59);
body.innerHTML = body.innerHTML + "<div id='collectable'; style='position: absolute; left: " + (colX*10-10) + "px; top:" + (colY*10-10) + "px; width: 10px; height: 10px; background-color: #f00; border: 0; padding: 0; margin: 0;'></div>";
}
function isBound(x, y){
if (x > 0 && x < 61){
if (y > 0 && y < 61){
return true;
}
}
return false;
}
function die(){
set("data", saves + "|" + score );
location.reload();
}
function update(){
if (paused == false){
if (direction == 1){
posY -= 1;
}else if(direction == 2){
posX += 1;
}else if(direction == 3){
posY += 1;
}else if(direction == 4){
posX -= 1;
}
if (isBound(posX, posY)){
function func(item, index, arr){
var x = item.split(",")[0];
var y = item.split(",")[1];
if(posX == x){
if(posY == y){
die();
}
}
}
snake.forEach(func);
snake.push(newTail(posX, posY));
if(wasCollected == false){
var rem = snake.shift();
var remObj = document.getElementById(rem);
remObj.parentNode.removeChild(remObj);
}else{
wasCollected = false;
}
}else{
die();
}
}
}
function keyDown(event){
if (event.key == "w"){
direction = 1;
}else if(event.key == "d"){
direction = 2;
}else if(event.key == "s"){
direction = 3;
}else if(event.key == "a"){
direction = 4;
}else if(event.key == "p"){
if (paused == true){
paused = false;
document.getElementById("PauseScreen").style.display = "none";
}else{
paused = true;
document.getElementById("PauseScreen").style.display = "";
}
}
}
function loadLeaderboard(){
if (get("data") != null){
saves = get("data");
function func(item, index, arr){
document.getElementById("Scoreboard").innerHTML += '<div><h2 id="' + item + '"; style="text-align: center; font-size: 20px; padding: 0; margin: 0; border: 0;">' + item.toString() + '</h2></div>';
}
saves.split("|").forEach(func);
}
}
function start(){
newCollectable();
snake.push(newTail(10, 15));
snake.push(newTail(11, 15));
snake.push(newTail(12, 15));
setTimeout(loadLeaderboard, 100);
setInterval(update, 100);
}
start();
</script>
</div>
<div id="PauseScreen"style="position: relative; display: none; width: 500px; margin-left: 50%; right: 250px;">
<h2 style="text-align: center; color: #f00; ">Game Paused</h2>
</div>
<div style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;">
<h3 style="text-align: center; font-size: 25px; color: #0f0; padding: 0; margin: 0; border: 0;">LEADERBOARD</h3>
</div>
<hr style="margin: 0px; width:calc(100% - 82px);" />
<div id="Scoreboard" style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;"></div>
<h3 style="position: absolute; right: 10px; bottom: 3px; color: #fff;">Designed by Derek in California</h3>
</body>
</html>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB