diff --git a/ToDo.txt b/ToDo.txt deleted file mode 100755 index 854f2d6..0000000 --- a/ToDo.txt +++ /dev/null @@ -1,53 +0,0 @@ -Server: - AccountInventory.cs - SetInventory isnt fully implimented - - ProjectMistData.cs - Data inside the sql doesnt match what is inside the database - - Emails: - Dont follow theme of website - - Admin Functions: - Dont inforce Admin on the API side - - Authentication ProductController - When the create account is called. right after the getaccount is called. - Have all New for database return the object they create - - Update API - Split apart the different routes and Functions - No more new / update -> only get / set - Make all apis return statuscodes - make all input types form's - make all getLoggedInUsers() -> make sure that i cant just call getLoggedInUserID - - Need to timeout email reset tokens - -Client: - Program - Probably need to turn on cors at some point - - Account - Need to add in settings / data pages - After a new account is created notify a user that they need to verify their email before logging in - - ProductController - Need to figure out new way to download purchased items as there is currently no way - - Store - Edit product needs created - Need to add cart back - Need to add in payment page - Need to add in payment success/failed - Need to add in Receipt page - - TopBar - No way to minimize the UI topbar on mobile - Not themed on mobile - - API - Some of the API's Changed. Need to go back and update the client API calls - -database - Need to create all the forign key policies \ No newline at end of file diff --git a/ToDo.yaml b/ToDo.yaml new file mode 100755 index 0000000..80938c7 --- /dev/null +++ b/ToDo.yaml @@ -0,0 +1,11 @@ +Server: + Emails: + Dont follow theme of website + + Need to timeout email reset tokens: + +Client: + + +database: + Add Applied Jobs Table \ No newline at end of file diff --git a/database/mistox.sql b/database/mistox.sql index a571c29..1308b01 100755 --- a/database/mistox.sql +++ b/database/mistox.sql @@ -15,7 +15,6 @@ CREATE TABLE IF NOT EXISTS `Account` ( `Role` varchar(45) DEFAULT NULL, `EmailToken` varchar(45) DEFAULT NULL, `DataServer` varchar(200) DEFAULT NULL, - `ServerRegion` varchar(10) DEFAULT NULL, UNIQUE(`Email`), UNIQUE(`UserName`), PRIMARY KEY (`ID`) @@ -57,13 +56,15 @@ CREATE TABLE IF NOT EXISTS `Resume` ( CREATE TABLE IF NOT EXISTS `ResumeExperienceBullet` ( `ID` int NOT NULL AUTO_INCREMENT, + `ResumeID` int NOT NULL, `ResumeExperienceID` int NOT NULL, `JobFunction` text NOT NULL, PRIMARY KEY (`ID`), + FOREIGN KEY (`ResumeID`) REFERENCES `Resume`(`ID`) ON DELETE CASCADE, FOREIGN KEY (`ResumeExperienceID`) REFERENCES `ResumeExperience`(`ID`) ON DELETE CASCADE ) AUTO_INCREMENT=1; - CREATE TABLE IF NOT EXISTS `ResumeMillitary` ( + CREATE TABLE IF NOT EXISTS `ResumeMilitary` ( `ID` int NOT NULL AUTO_INCREMENT, `ResumeID` int NOT NULL, `Country` char(2) NOT NULL, @@ -75,13 +76,15 @@ CREATE TABLE IF NOT EXISTS `Resume` ( FOREIGN KEY (`ResumeID`) REFERENCES `Resume`(`ID`) ON DELETE CASCADE ) AUTO_INCREMENT=1; - CREATE TABLE IF NOT EXISTS `ResumeMillitaryBullet` ( + CREATE TABLE IF NOT EXISTS `ResumeMilitaryBullet` ( `ID` int NOT NULL AUTO_INCREMENT, - `ResumeMillitaryID` int NOT NULL, - `Achevement` varchar(100) NOT NULL, + `ResumeID` int NOT NULL, + `ResumeMilitaryID` int NOT NULL, + `Achievement` varchar(100) NOT NULL, `Description` text DEFAULT NULL, PRIMARY KEY (`ID`), - FOREIGN KEY (`ResumeMillitaryID`) REFERENCES `ResumeMillitary`(`ID`) ON DELETE CASCADE + FOREIGN KEY (`ResumeID`) REFERENCES `Resume`(`ID`) ON DELETE CASCADE, + FOREIGN KEY (`ResumeMilitaryID`) REFERENCES `ResumeMilitary`(`ID`) ON DELETE CASCADE ) AUTO_INCREMENT=1; CREATE TABLE IF NOT EXISTS `ResumeEducation` ( @@ -146,17 +149,26 @@ CREATE TABLE IF NOT EXISTS `Company` ( `Name` varchar(100) DEFAULT NULL, `Email` varchar(255) DEFAULT NULL, `EmailVerified` boolean DEFAULT 0, - `WebsiteURL` VARCHAR(255) DEFAULT NULL, - `LogoURL` VARCHAR(2048) DEFAULT NULL, - `Phone` VARCHAR(20) DEFAULT NULL, + `WebsiteURL` varchar(255) DEFAULT NULL, + `LogoURL` varchar(2048) DEFAULT NULL, + `Phone` varchar(20) DEFAULT NULL, `PostalCode` varchar(20) NOT NULL, - `Country` CHAR(2) NOT NULL, + `Country` char(2) NOT NULL, `StateOrRegion` varchar(100) NOT NULL, - `City` VARCHAR(100), - `Description` TEXT, + `City` varchar(100), + `Description` text, PRIMARY KEY (`ID`) ) AUTO_INCREMENT=1; +CREATE TABLE IF NOT EXISTS `Employee` ( + `ID` int NOT NULL AUTO_INCREMENT, + `AccountID` int NOT NULL, + `CompanyID` int NOT NULL, + PRIMARY KEY (`ID`), + FOREIGN KEY (`AccountID`) REFERENCES `Account`(`ID`) ON DELETE CASCADE, + FOREIGN KEY (`CompanyID`) REFERENCES `Company`(`ID`) ON DELETE CASCADE +) AUTO_INCREMENT=1; + CREATE TABLE IF NOT EXISTS `JobListing` ( `ID` int NOT NULL AUTO_INCREMENT, `CompanyID` int NOT NULL, @@ -170,6 +182,9 @@ CREATE TABLE IF NOT EXISTS `JobListing` ( `JobType` varchar(20) NOT NULL, `Remote` boolean DEFAULT 0, `Description` text NOT NULL, + `CreatedTime` datetime Default NULL, + `ModifiedTime` datetime DEFAULT NULL, + `IsDeleted` boolean Default 0, PRIMARY KEY (`ID`), FOREIGN KEY (`CompanyID`) REFERENCES `Company`(`ID`) ON DELETE CASCADE ) AUTO_INCREMENT=1; diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index ef2ac3a..4a532da 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -5,10 +5,12 @@ using System.Security.Claims; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; using BoredCareers.Entities; +using Microsoft.AspNetCore.Http.HttpResults; +using System.Web.Http; namespace BoredCareers.Controllers { [ApiController] - [Route("api/account/[controller]")] + [Route("api/account/")] public class AuthenticationController : MistoxControllerBase { EmailService _emailContext; @@ -26,7 +28,7 @@ namespace BoredCareers.Controllers { 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" }; + return NotFound("Too many failed password attempts. Please reset your password"); } } if (BCrypt.Net.BCrypt.Verify(PasswordHash, test.PasswordHash)) { @@ -34,7 +36,8 @@ namespace BoredCareers.Controllers { await _databaseService.SetAccount(test); List claims = new List() { - new Claim("ID", test.ID.ToString()) + new Claim("ID", test.ID.ToString()), + new Claim(ClaimTypes.NameIdentifier, test.ID.ToString()) }; await HttpContext.SignInAsync( @@ -46,21 +49,20 @@ namespace BoredCareers.Controllers { } ); return test; - } - else { + } else { test.CurrentPasswordAttempts += 1; await _databaseService.SetAccount(test); - return new Account() { Error = "Wrong password" }; + return Ok(new Account() { ID = -1, UserName = "Wrong Password" }); } - } - else { + } 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 NotFound("A new verify email has been sent. \n Note only 1 email send every 5 mintes"); } } - return new Account() { Error = "User doesn't exist" }; + return NotFound("Account Not Found"); } catch (Exception ex) { - return new Account() { Error = ex.Message }; + Console.WriteLine("Login Error: " + ex.Message); + return NotFound(); } } @@ -70,37 +72,35 @@ namespace BoredCareers.Controllers { try { if (await _databaseService.GetAccount(UserName.ToLower()) == null) { if (await _databaseService.GetAccount(Email.ToLower()) == null) { - Account? created = new Account() { + 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; + Account? loadedAccount = await _databaseService.GetAccount(Email.ToLower()); + if (loadedAccount != null) { + await SendVerify(loadedAccount.UserName); + return Ok(loadedAccount); } - return new Account() { Error = "Unknown Error" }; + return NotFound("Unable to create the account"); + } else { + return NotFound("Email is already in use"); } - else { - return new Account() { Error = "Email is already in use" }; - } - } - else { - return new Account() { Error = "UserName is taken" }; + } else { + return NotFound("UserName is taken"); } } catch (Exception ex) { - Console.WriteLine("Error: " + ex.Message); - return new Account() { Error = ex.Message }; + Console.WriteLine("Register Error: " + ex.Message); + return NotFound(); } } [Route("changepassword")] [HttpPost] - public async Task> ChangePassword([FromForm] string OldPassword, [FromForm] string NewPassword) { + public async Task ChangePassword([FromForm] string OldPassword, [FromForm] string NewPassword) { try { if (isLoggedIn()) { Account user = await getLoggedInUser(); @@ -108,12 +108,13 @@ namespace BoredCareers.Controllers { user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword); user.CurrentPasswordAttempts = 0; await _databaseService.SetAccount(user); - return true; + return Ok(); } } - return false; - } catch { - return false; + return NotFound(); + } catch (Exception ex) { + Console.WriteLine("ChangePassword Error: " + ex.Message); + return NotFound(); } } @@ -126,31 +127,37 @@ namespace BoredCareers.Controllers { user.FailedPasswordLock = AccountLock; user.CurrentPasswordAttempts = 0; await _databaseService.SetAccount(user); - return "Account Lock Status Updated"; + return Ok(); } - return "Unknown Error Occurred"; + return NotFound(); } catch (Exception ex) { - return ex.Message; + Console.WriteLine("ToggleAccountLock Error: " + ex.Message); + return NotFound(); } } [Route("get")] [HttpPost] - public async Task> Get() { + public async Task> Get() { try { if (isLoggedIn()) { - return await getLoggedInUser(); + return Ok(await getLoggedInUser()); } - return Ok(); - } catch { - return Ok(); + return NotFound(); + } catch (Exception ex) { + Console.WriteLine("Get Error: " + ex); + return NotFound(); } } [Route("logout")] [HttpPost] - public async Task Logout() { - await HttpContext.SignOutAsync(); + public async Task Logout() { + if (isLoggedIn()) { + await HttpContext.SignOutAsync(); + return Ok(); + } + return NotFound(); } [Route("sendverifyemail")] @@ -266,18 +273,19 @@ namespace BoredCareers.Controllers { [Route("delete")] [HttpPost] - public async Task> delete([FromForm] string Password) { + public async Task 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 Ok(); } } - return false; - } catch { - return false; + return NotFound(); + } catch (Exception ex) { + Console.WriteLine("Delete Error: " + ex.Message); + return NotFound(); } } diff --git a/src/Server/Controllers/CartController.cs b/src/Server/Controllers/CartController.cs deleted file mode 100644 index 597d369..0000000 --- a/src/Server/Controllers/CartController.cs +++ /dev/null @@ -1,69 +0,0 @@ -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> GetCart() { - try { - if (isLoggedIn()) { - return Ok(await _databaseService.GetCart(getLoggedInUserID())); - } - return StatusCode(500); - } catch { - return StatusCode(500); - } - } - - [Route("add")] - [HttpPost] - public async Task 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 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 ClearCart() { - try { - if (isLoggedIn()) { - await _databaseService.ClearCart(getLoggedInUserID()); - return Ok(); - } - return StatusCode(500); - } catch { - return StatusCode(500); - } - } - } -} \ No newline at end of file diff --git a/src/Server/Controllers/CompanyController.cs b/src/Server/Controllers/CompanyController.cs new file mode 100644 index 0000000..cb644a2 --- /dev/null +++ b/src/Server/Controllers/CompanyController.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Mvc; +using BoredCareers.Services.DatabaseService; +using BoredCareers.Entities; +using System.Web.Http; + +namespace BoredCareers.Controllers { + [ApiController] + [Route("api/company")] + public class CompanyController : MistoxControllerBase { + + public CompanyController(DatabaseService db) : base(db) {} + + [HttpGet] + public async Task GetCompany(int CompanyID) { + if (isLoggedIn()) { + Company? company = await _databaseService.GetCompany(CompanyID); + if (company != null) { + return Ok(company); + } + } + return NotFound(); + } + + [HttpPost] + public async Task SetCompany([FromBody] Company company) { + if (isLoggedIn()) { + if (await isLoggedInUserEmployeeOf(company.ID)) { + await _databaseService.SetCompany(company); + return Ok(); + } + } + return NotFound(); + } + + [HttpDelete] + public async Task DeleteCompany(int CompanyID) { + if (isLoggedIn()) { + if (await isLoggedInUserEmployeeOf(CompanyID)) { + await _databaseService.DeleteCompany(CompanyID); + return Ok(); + } + } + return NotFound(); + } + + } + +} diff --git a/src/Server/Controllers/JobListingController.cs b/src/Server/Controllers/JobListingController.cs new file mode 100644 index 0000000..495fb0b --- /dev/null +++ b/src/Server/Controllers/JobListingController.cs @@ -0,0 +1,53 @@ +using Microsoft.AspNetCore.Mvc; +using BoredCareers.Services.DatabaseService; +using BoredCareers.Entities; +using System.Web.Http; + +namespace BoredCareers.Controllers { + [ApiController] + [Route("api/joblisting")] + public class JobListingController : MistoxControllerBase { + + public JobListingController(DatabaseService db) : base(db) {} + + [HttpGet("{JobListingID}")] + public async Task GetJobListing([FromRoute] int JobListingID) { + var jobListing = await _databaseService.GetJobListing(JobListingID); + if (jobListing != null) { + return Ok(jobListing); + } + return NotFound(); + } + + [HttpGet] + public async Task GetJobListings(int Page = 1, int PageQuantity = 25) { + JobListing[] jobListings = await _databaseService.GetJobListingPage(Page, PageQuantity); + return Ok(jobListings); + } + + [HttpPost] + public async Task SetJobListing([FromBody] JobListing JobListing) { + if (isLoggedIn()) { + if (await isLoggedInUserEmployeeOf(JobListing.CompanyID)) { + await _databaseService.SetJobListing(JobListing); + } + } + return NotFound(); + } + + [HttpDelete] + public async Task DeleteJobListing(int JobListingID) { + if (isLoggedIn()) { + JobListing? jobListing = await _databaseService.GetJobListing(JobListingID); + if (jobListing != null) { + if (await isLoggedInUserEmployeeOf(JobListingID)) { + await _databaseService.DeleteJobListing(JobListingID); + } + } + } + return NotFound(); + } + + } + +} diff --git a/src/Server/Controllers/MistoxControllerBase.cs b/src/Server/Controllers/MistoxControllerBase.cs index daed8cc..0084227 100644 --- a/src/Server/Controllers/MistoxControllerBase.cs +++ b/src/Server/Controllers/MistoxControllerBase.cs @@ -35,6 +35,16 @@ namespace BoredCareers.Controllers { } } + public async Task isLoggedInUserEmployeeOf(int CompanyID) { + Employee[] employees = await _databaseService.GetEmployees(CompanyID); + foreach (Employee cur in employees) { + if (getLoggedInUserID() == cur.AccountID) { + return true; + } + } + return false; + } + 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) { diff --git a/src/Server/Controllers/PaymentController.cs b/src/Server/Controllers/PaymentController.cs index 17917c7..31e0537 100755 --- a/src/Server/Controllers/PaymentController.cs +++ b/src/Server/Controllers/PaymentController.cs @@ -1,11 +1,10 @@ using Microsoft.AspNetCore.Mvc; using BoredCareers.Controllers.Payment; using BoredCareers.Services.DatabaseService; -using BoredCareers.Entities; namespace BoredCareers.Controllers { [ApiController] - [Route("api/payment/[controller]")] + [Route("api/payment")] public class PaymentController : MistoxControllerBase { IPayment _paymentService; @@ -20,37 +19,11 @@ namespace BoredCareers.Controllers { // Add new payment plugins here } - [Route("getcheckouttoken")] - [HttpPost] - public async Task 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] + [HttpGet] public IActionResult GetPublicKey() { - try { - return Ok(IPayment._PublicKey); - } catch (Exception ex) { - return NotFound(ex.ToString()); - } + return Ok(IPayment._PublicKey); } - [Route("response")] [HttpPost] public async Task paymentWebhook() { try { diff --git a/src/Server/Controllers/PaymentMethods/IPayment.cs b/src/Server/Controllers/PaymentMethods/IPayment.cs index 3ade142..73196d3 100644 --- a/src/Server/Controllers/PaymentMethods/IPayment.cs +++ b/src/Server/Controllers/PaymentMethods/IPayment.cs @@ -8,7 +8,6 @@ namespace BoredCareers.Controllers.Payment { 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); } diff --git a/src/Server/Controllers/PaymentMethods/StripeIntents.cs b/src/Server/Controllers/PaymentMethods/StripeIntents.cs index 2e5f12f..fca5a5e 100644 --- a/src/Server/Controllers/PaymentMethods/StripeIntents.cs +++ b/src/Server/Controllers/PaymentMethods/StripeIntents.cs @@ -1,6 +1,5 @@ using BoredCareers.Controllers.Payment; using BoredCareers.Services.DatabaseService; -using BoredCareers.Entities; namespace BoredCareers.Controllers { @@ -12,72 +11,6 @@ namespace BoredCareers.Controllers { _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() { "line_items" }, - LineItems = new List() - }; - - List prods = new List(); - - // 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 { - { "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") { @@ -114,22 +47,7 @@ namespace BoredCareers.Controllers { } } - // 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); } diff --git a/src/Server/Controllers/ProductController.cs b/src/Server/Controllers/ProductController.cs deleted file mode 100755 index 1903df2..0000000 --- a/src/Server/Controllers/ProductController.cs +++ /dev/null @@ -1,143 +0,0 @@ -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> CreateProduct([FromForm] Product obj, [FromForm] IFormFile[] images) { - try { - if (isLoggedIn()) { - Account user = await getLoggedInUser(); - if (user.Role == "Admin") { - List building = new List(); - 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> 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 GetAllProducts() { - try { - return await _databaseService.GetAllProducts(); - } catch { - return Array.Empty(); - } - } - - [Route("delete")] - [HttpPost] - public async Task> 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 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> 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 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(); - } - } - - } - -} diff --git a/src/Server/Controllers/ResumeController.cs b/src/Server/Controllers/ResumeController.cs new file mode 100644 index 0000000..65b9099 --- /dev/null +++ b/src/Server/Controllers/ResumeController.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Mvc; +using BoredCareers.Services.DatabaseService; +using BoredCareers.Entities; +using System.Web.Http; + +namespace BoredCareers.Controllers { + [ApiController] + [Route("api/resume")] + public class ResumeController : MistoxControllerBase { + + public ResumeController(DatabaseService db) : base(db) {} + + [HttpGet] + public async Task GetResume(int? ResumeID) { + if (ResumeID != null) { + Resume? resume = await _databaseService.GetResume(ResumeID.Value); + if (resume != null) { + return Ok(resume); + } + }else{ + if (isLoggedIn()) { + int accountID = getLoggedInUserID(); + Resume[] resumes = await _databaseService.GetResumes(accountID); + return Ok(resumes); + } + } + return NotFound(); + } + + [HttpPost] + public async Task SetResume([FromBody] Resume resume) { + if (isLoggedIn()) { + int AccountID = getLoggedInUserID(); + if (resume.AccountID == AccountID) { + await _databaseService.SetResume(resume); + return Ok(); + } + } + return NotFound(); + } + + [HttpDelete] + public async Task DeleteResume(int ResumeID) { + if (isLoggedIn()){ + int accountID = getLoggedInUserID(); + Resume? resume = await _databaseService.GetResume(ResumeID); + if (resume != null && resume.AccountID == accountID) { + await _databaseService.DeleteResume(ResumeID); + return Ok(); + } + } + return NotFound(); + } + + } +} \ No newline at end of file diff --git a/src/Server/Entities/Company.cs b/src/Server/Entities/Company.cs index fe42507..e0a5a97 100644 --- a/src/Server/Entities/Company.cs +++ b/src/Server/Entities/Company.cs @@ -15,19 +15,10 @@ namespace BoredCareers.Entities { public string Description { get; set; } = ""; } - public class JobListing { + public class Employee { public int ID { get; set; } // PK + public int AccountID { get; set; } // FK public int CompanyID { get; set; } // FK - public string Title { get; set; } = ""; - public string PostalCode { get; set; } = ""; - public string Country { get; set; } = ""; // 2 Letter Country Code - public string StateOrRegion { get; set; } = ""; - public string City { get; set; } = ""; - public int SalaryMin { get; set; } = 0; - public int SalaryMax { get; set; } = 0; - public string JobType { get; set; } = ""; - public bool Remote { get; set; } = false; - public string Description { get; set; } = ""; } } \ No newline at end of file diff --git a/src/Server/Entities/JobListing.cs b/src/Server/Entities/JobListing.cs new file mode 100644 index 0000000..f88744e --- /dev/null +++ b/src/Server/Entities/JobListing.cs @@ -0,0 +1,21 @@ +namespace BoredCareers.Entities { + + public class JobListing { + public int ID { get; set; } // PK + public int CompanyID { get; set; } // FK + public string Title { get; set; } = ""; + public string PostalCode { get; set; } = ""; + public string Country { get; set; } = ""; // 2 Letter Country Code + public string StateOrRegion { get; set; } = ""; + public string City { get; set; } = ""; + public int SalaryMin { get; set; } = 0; + public int SalaryMax { get; set; } = 0; + public string JobType { get; set; } = ""; + public bool Remote { get; set; } = false; + public string Description { get; set; } = ""; + public DateTime CreatedTime { get; set; } + public DateTime ModifiedTime { get; set; } + public bool IsDeleted { get; set; } = false; + } + +} \ No newline at end of file diff --git a/src/Server/Entities/Resume.cs b/src/Server/Entities/Resume.cs index ae1d175..55b58c0 100644 --- a/src/Server/Entities/Resume.cs +++ b/src/Server/Entities/Resume.cs @@ -12,6 +12,13 @@ namespace BoredCareers.Entities { public string StateOrRegion { get; set; } = ""; public string City { get; set; } = ""; public bool IsActive { get; set; } = false; + public ResumeExperience[] Experience { get; set; } = []; + public ResumeMilitary Millitary { get; set; } = new ResumeMilitary(); + public ResumeEducation[] Educations { get; set; } = []; + public ResumeSkill[] Skills { get; set; } = []; + public ResumeLanguage[] Languages { get; set; } = []; + public ResumeCertification[] Certification { get; set; } = []; + public ResumeProject[] Projects { get; set; } = []; } public class ResumeExperience { @@ -26,15 +33,17 @@ namespace BoredCareers.Entities { public DateTime DateStarted { get; set; } = new DateTime(); public bool StillEmployed { get; set; } = false; public DateTime DateEnded { get; set; } = new DateTime(); + public ResumeExperienceBullet[] ExperienceBullets { get; set; } = []; } public class ResumeExperienceBullet { public int ID { get; set; } // PK + public int ResumeID { get; set; } // FK public int ResumeExperienceID { get; set; } // FK public string JobFunction { get; set; } = ""; } - public class ResumeMillitary { + public class ResumeMilitary { public int ID { get; set; } // PK public int ResumeID { get; set; } // FK public string Country { get; set; } = ""; // 2 Letter Country Code @@ -42,12 +51,14 @@ namespace BoredCareers.Entities { public DateTime DateStarted { get; set; } = new DateTime(); public bool StillServing { get; set; } = false; public DateTime DateEnded { get; set; } = new DateTime(); + public ResumeMilitaryBullet[] MillitaryBullets = []; } - public class ResumeMillitaryBullet { + public class ResumeMilitaryBullet { public int ID { get; set; } // PK - public int ResumeMillitaryID { get; set; } // FK - public string Achevement { get; set; } = ""; + public int ResumeID { get; set; } // FK + public int ResumeMilitaryID { get; set; } // FK + public string Achievement { get; set; } = ""; public string Description { get; set; } = ""; } diff --git a/src/Server/Program.cs b/src/Server/Program.cs index 15d312b..bed8db4 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -2,7 +2,9 @@ using Microsoft.AspNetCore.Authentication.Cookies; using BoredCareers.Controllers.Payment; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; +using System.Threading.RateLimiting; using Stripe; +using System.Security.Claims; var builder = WebApplication.CreateBuilder(args); @@ -90,9 +92,26 @@ builder.Services.AddAuthentication( options => { options.SlidingExpiration = true; }); -builder.Services.AddCors( o => o.AddDefaultPolicy( builder => { +builder.Services.AddCors(o => o.AddDefaultPolicy(builder => { builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); // No CORS -} ) ); +})); + +builder.Services.AddRateLimiter(options => { + options.AddPolicy("PerUserPolicy", httpContext => { + var userId = httpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value + ?? httpContext.User.Identity?.Name + ?? httpContext.Connection.RemoteIpAddress?.ToString(); + + return RateLimitPartition.GetTokenBucketLimiter(userId, key => new TokenBucketRateLimiterOptions { + TokenLimit = 10, // max 10 requests + QueueProcessingOrder = QueueProcessingOrder.OldestFirst, + QueueLimit = 0, + ReplenishmentPeriod = TimeSpan.FromSeconds(15), + TokensPerPeriod = 2, + AutoReplenishment = true + }); + }); +}); // Pages Service builder.Services.AddControllers(); @@ -113,7 +132,7 @@ app.UseCors(); app.UseRouting(); app.UseAuthentication(); -app.MapControllers(); +app.MapControllers().RequireRateLimiting("perUserPolicy"); app.MapFallbackToFile("index.html"); diff --git a/src/Server/Services/DatabaseService/Account.cs b/src/Server/Services/DatabaseService/Account.cs index ca84844..ae527da 100755 --- a/src/Server/Services/DatabaseService/Account.cs +++ b/src/Server/Services/DatabaseService/Account.cs @@ -21,10 +21,7 @@ namespace BoredCareers.Services.DatabaseService { using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) { while( await reader.ReadAsync() ) { - if( reader == null ) { - break; - } - + if( reader == null ) { break; } int _id = reader.GetInt32("ID"); string _username = reader.GetString("UserName"); string _email = reader.GetString("Email"); @@ -56,7 +53,7 @@ namespace BoredCareers.Services.DatabaseService { return account; } - public async Task GetAccount( int ID ) { + public async Task GetAccount( int AccountID ) { Account? account = null; using( MySqlConnection connection = GetConnection() ) { connection.Open(); @@ -67,7 +64,7 @@ namespace BoredCareers.Services.DatabaseService { "; MySqlCommand cmd = new MySqlCommand(command, connection); - cmd.Parameters.AddWithValue("@ID", ID); + cmd.Parameters.AddWithValue("@ID", AccountID); using( DbDataReader reader = await cmd.ExecuteReaderAsync() ) { while( await reader.ReadAsync() ) { @@ -144,7 +141,7 @@ namespace BoredCareers.Services.DatabaseService { } } - public async Task DeleteAccount( int ID ) { + public async Task DeleteAccount( int AccountID ) { using( MySqlConnection connection = GetConnection() ) { MySqlCommand cmd; connection.Open(); @@ -153,7 +150,7 @@ namespace BoredCareers.Services.DatabaseService { DELETE FROM Account WHERE ID = @ID; "; cmd = new MySqlCommand( command, connection ); - cmd.Parameters.AddWithValue("@ID", ID); + cmd.Parameters.AddWithValue("@ID", AccountID); await cmd.ExecuteNonQueryAsync(); } diff --git a/src/Server/Services/DatabaseService/Company.cs b/src/Server/Services/DatabaseService/Company.cs new file mode 100644 index 0000000..2eafd16 --- /dev/null +++ b/src/Server/Services/DatabaseService/Company.cs @@ -0,0 +1,115 @@ +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 GetCompany( int CompanyID ) { + Company? company = null; + using( MySqlConnection connection = GetConnection() ) { + connection.Open(); + string command = @" + SELECT * + FROM Company + WHERE ID = @ID; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", CompanyID); + + 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 _email = reader.GetString("Email"); + bool _emailVerified = reader.GetBoolean("EmailVerified"); + string _websiteurl = reader.GetString("WebsiteURL"); + string _logourl = reader.GetString( "LogoURL" ); + string _phone = reader.GetString( "Phone" ); + string _postalcode = reader.GetString( "PostalCode" ); + string _country = reader.GetString( "Country" ); + string _state = reader.GetString( "StateOrRegion" ); + string _city = reader.GetString( "City" ); + string _description = reader.GetString( "Description" ); + + company = new Company() { + ID = _id, + Name = _name, + Email = _email, + EmailVerified = _emailVerified, + WebsiteURL = _websiteurl, + LogoURL = _logourl, + Phone = _phone, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + Description = _description + }; + } + } + } + return company; + } + + public async Task SetCompany( Company company ) { + using( MySqlConnection connection = GetConnection() ) { + connection.Open(); + + string command = @" + INSERT INTO Account + (ID,Name,Email,EmailVerified,WebsiteURL,LogoURL,Phone,PostalCode,Country,StateOrRegion,City,Description) + VALUES + (@ID,@Name,@Email,@EmailVerified,@WebsiteURL,@LogoURL,@Phone,@PostalCode,@Country,@StateOrRegion,@City,@Description); + ON DUPLICATE KEY UPDATE + Name = @Name, + Email = @Email, + EmailVerified = @EmailVerified, + WebsiteURL = @WebsiteURL, + LogoURL = @LogoURL, + Phone = @Phone, + PostalCode = @PostalCode, + Country = @Country, + StateOrRegion = @StateOrRegion; + City = @City, + Description = @Description; + "; + + MySqlCommand cmd = new MySqlCommand( command , connection); + cmd.Parameters.AddWithValue("@ID", company.ID); + cmd.Parameters.AddWithValue("@Name", company.Name); + cmd.Parameters.AddWithValue("@Email", company.Email); + cmd.Parameters.AddWithValue("@EmailVerified", company.EmailVerified); + cmd.Parameters.AddWithValue("@WebsiteURL", company.WebsiteURL); + cmd.Parameters.AddWithValue("@LogoURL", company.LogoURL); + cmd.Parameters.AddWithValue("@Phone", company.Phone); + cmd.Parameters.AddWithValue("@PostalCode", company.PostalCode); + cmd.Parameters.AddWithValue("@Country", company.Country); + cmd.Parameters.AddWithValue("@StateOrRegion", company.StateOrRegion); + cmd.Parameters.AddWithValue("@City", company.City); + cmd.Parameters.AddWithValue("@Description", company.Description); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task DeleteCompany( int CompanyID ) { + using( MySqlConnection connection = GetConnection() ) { + MySqlCommand cmd; + connection.Open(); + + string command = @" + DELETE FROM Company WHERE ID = @ID; + "; + cmd = new MySqlCommand( command, connection ); + cmd.Parameters.AddWithValue("@ID", CompanyID); + + await cmd.ExecuteNonQueryAsync(); + } + } + + } +} diff --git a/src/Server/Services/DatabaseService/Employee.cs b/src/Server/Services/DatabaseService/Employee.cs new file mode 100644 index 0000000..e317e89 --- /dev/null +++ b/src/Server/Services/DatabaseService/Employee.cs @@ -0,0 +1,79 @@ +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 GetEmployees( int CompanyID ) { + List employees = new List(); + using( MySqlConnection connection = GetConnection() ) { + connection.Open(); + string command = @" + SELECT * + FROM Employee + WHERE ID = @ID; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", CompanyID); + + 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 _companyid = reader.GetInt32("CompanyID"); + + employees.Add(new Employee() { + ID = _id, + AccountID = _accountid, + CompanyID = _companyid + }); + } + } + } + return employees.ToArray(); + } + + public async Task SetEmployee( Employee employee ) { + using( MySqlConnection connection = GetConnection() ) { + connection.Open(); + + string command = @" + INSERT INTO Employee + (ID,AccountID,CompanyID) + VALUES + (@ID,@AccountID,@CompanyID); + ON DUPLICATE KEY UPDATE + AccountID = @AccountID, + CompanyID = @CompanyID; + "; + + MySqlCommand cmd = new MySqlCommand( command , connection); + cmd.Parameters.AddWithValue("@ID", employee.ID); + cmd.Parameters.AddWithValue("@AccountID", employee.AccountID); + cmd.Parameters.AddWithValue("@CompanyID", employee.CompanyID); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task DeleteEmployee( int EmployeeID ) { + using( MySqlConnection connection = GetConnection() ) { + MySqlCommand cmd; + connection.Open(); + + string command = @" + DELETE FROM Employee WHERE ID = @ID; + "; + cmd = new MySqlCommand( command, connection ); + cmd.Parameters.AddWithValue("@ID", EmployeeID); + + await cmd.ExecuteNonQueryAsync(); + } + } + + } +} diff --git a/src/Server/Services/DatabaseService/JobListing.cs b/src/Server/Services/DatabaseService/JobListing.cs new file mode 100644 index 0000000..384fa84 --- /dev/null +++ b/src/Server/Services/DatabaseService/JobListing.cs @@ -0,0 +1,187 @@ +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 GetJobListingPage(int PageNumber, int CountPerPage) { + List joblistings = new List(); + using (MySqlConnection connection = GetConnection()) { + connection.Open(); + string command = @" + SELECT * + FROM JobListing + WHERE IsDeleted = FALSE + ORDER BY CreatedTime DESC + LIMIT @PageSize OFFSET @PageNumber; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@PageSize", CountPerPage); + cmd.Parameters.AddWithValue("@PageNumber", (PageNumber - 1) * CountPerPage); + + using (DbDataReader reader = await cmd.ExecuteReaderAsync()) { + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _companyid = reader.GetInt32("CompanyID"); + string _title = reader.GetString("Title"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + int _salarymin = reader.GetInt32("SalaryMin"); + int _salarymax = reader.GetInt32("SalaryMax"); + string _jobtype = reader.GetString("JobType"); + bool _remote = reader.GetBoolean("Remote"); + string _description = reader.GetString("Description"); + DateTime _createtime = reader.GetDateTime("CreatedTime"); + DateTime _modifiedtime = reader.GetDateTime("ModifiedTime"); + bool _isdeleted = reader.GetBoolean("IsDeleted"); + + joblistings.Add(new JobListing() { + ID = _id, + CompanyID = _companyid, + Title = _title, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + SalaryMin = _salarymin, + SalaryMax = _salarymax, + JobType = _jobtype, + Remote = _remote, + Description = _description, + CreatedTime = _createtime, + ModifiedTime = _modifiedtime, + IsDeleted = _isdeleted + }); + } + } + } + return joblistings.ToArray(); + } + + public async Task GetJobListing(int JobListingID) { + JobListing? joblisting = null; + using (MySqlConnection connection = GetConnection()) { + connection.Open(); + string command = @" + SELECT * + FROM JobListing + WHERE ID = @ID; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", JobListingID); + + using (DbDataReader reader = await cmd.ExecuteReaderAsync()) { + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _companyid = reader.GetInt32("CompanyID"); + string _title = reader.GetString("Title"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + int _salarymin = reader.GetInt32("SalaryMin"); + int _salarymax = reader.GetInt32("SalaryMax"); + string _jobtype = reader.GetString("JobType"); + bool _remote = reader.GetBoolean("Remote"); + string _description = reader.GetString("Description"); + DateTime _createtime = reader.GetDateTime("CreatedTime"); + DateTime _modifiedtime = reader.GetDateTime("ModifiedTime"); + bool _isdeleted = reader.GetBoolean("IsDeleted"); + + joblisting = new JobListing() { + ID = _id, + CompanyID = _companyid, + Title = _title, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + SalaryMin = _salarymin, + SalaryMax = _salarymax, + JobType = _jobtype, + Remote = _remote, + Description = _description, + CreatedTime = _createtime, + ModifiedTime = _modifiedtime, + IsDeleted = _isdeleted + }; + } + } + } + return joblisting; + } + + public async Task SetJobListing( JobListing jobListing ) { + using( MySqlConnection connection = GetConnection() ) { + connection.Open(); + + string command = @" + INSERT INTO JobListing + (ID,CompanyID,Title,PostalCode,Country,StateOrRegion,City,SalaryMin,SalaryMax,JobType,Remote,Description,CreatedTime,ModifiedTime,IsDeleted) + VALUES + (@ID,@CompanyID,@Title,@PostalCode,@Country,@StateOrRegion,@City,@SalaryMin,@SalaryMax,@JobType,@Remote,@Description,@CreatedTime,@ModifiedTime,@IsDeleted); + ON DUPLICATE KEY UPDATE + CompanyID = @CompanyID, + Title = @Title, + PostalCode = @PostalCode, + Country = @Country, + StateOrRegion = @StateOrRegion, + City = @City, + SalaryMin = @SalaryMin, + SalaryMax = @SalaryMax, + JobType = @JobType, + Remote = @Remote, + Description = @Description, + CreatedTime = @CreatedTime, + ModifiedTime = @ModifiedTime, + IsDeleted = @IsDeleted; + "; + + MySqlCommand cmd = new MySqlCommand( command , connection); + cmd.Parameters.AddWithValue("@ID", jobListing.ID); + cmd.Parameters.AddWithValue("@CompanyID", jobListing.CompanyID); + cmd.Parameters.AddWithValue("@Title", jobListing.Title); + cmd.Parameters.AddWithValue("@PostalCode", jobListing.PostalCode); + cmd.Parameters.AddWithValue("@Country", jobListing.Country); + cmd.Parameters.AddWithValue("@StateOrRegion", jobListing.StateOrRegion); + cmd.Parameters.AddWithValue("@City", jobListing.City); + cmd.Parameters.AddWithValue("@SalaryMin", jobListing.SalaryMin); + cmd.Parameters.AddWithValue("@SalaryMax", jobListing.SalaryMax); + cmd.Parameters.AddWithValue("@JobType", jobListing.JobType); + cmd.Parameters.AddWithValue("@Remote", jobListing.Remote); + cmd.Parameters.AddWithValue("@Description", jobListing.Description); + cmd.Parameters.AddWithValue("@CreatedTime", jobListing.CreatedTime.ToUniversalTime()); + cmd.Parameters.AddWithValue("@ModifiedTime", jobListing.ModifiedTime.ToUniversalTime()); + cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task DeleteJobListing( int JobListingID ) { + using( MySqlConnection connection = GetConnection() ) { + MySqlCommand cmd; + connection.Open(); + + string command = @" + UPDATE JobListing + SET IsDeleted = TRUE + WHERE ID = @ID; + "; + cmd = new MySqlCommand( command, connection ); + cmd.Parameters.AddWithValue("@ID", JobListingID); + + await cmd.ExecuteNonQueryAsync(); + } + } + + } +} diff --git a/src/Server/Services/DatabaseService/Resume.cs b/src/Server/Services/DatabaseService/Resume.cs new file mode 100644 index 0000000..5050a10 --- /dev/null +++ b/src/Server/Services/DatabaseService/Resume.cs @@ -0,0 +1,236 @@ +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 GetResumes(int AccountID) { + List resumes = new List(); + using (MySqlConnection connection = GetConnection()) { + connection.Open(); + string command = @" + SELECT * + FROM Resume + 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"); + string _name = reader.GetString("Name"); + string _field = reader.GetString("Field"); + string _email = reader.GetString("Email"); + string _phonenumber = reader.GetString("PhoneNumber"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + bool _isactive = reader.GetBoolean("IsActive"); + + resumes.Add( new Resume() { + ID = _id, + AccountID = _accountid, + Name = _name, + Field = _field, + Email = _email, + PhoneNumber = _phonenumber, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + IsActive = _isactive + } ); + } + } + } + return resumes.ToArray(); + } + + public async Task GetResume(int ResumeID) { + // Open connections for multi-threaded request + MySqlConnection resumeConnection = GetConnection(); + MySqlConnection ResumeExperienceConnection = GetConnection(); + MySqlConnection ResumeExperienceBulletConnection = GetConnection(); + MySqlConnection ResumeMilitaryConnection = GetConnection(); + MySqlConnection ResumeMilitaryBulletConnection = GetConnection(); + MySqlConnection ResumeEducationConnection = GetConnection(); + MySqlConnection ResumeSkillConnection = GetConnection(); + MySqlConnection ResumeLanguageConnection = GetConnection(); + MySqlConnection ResumeCertificationConnection = GetConnection(); + MySqlConnection ResumeProjectConnection = GetConnection(); + + // Open the connections + Task resumeopen = resumeConnection.OpenAsync(); + Task resumeexperienceopen = ResumeExperienceConnection.OpenAsync(); + Task resumeexperiencebulletopen = ResumeExperienceBulletConnection.OpenAsync(); + Task resumemilitaryopen = ResumeMilitaryConnection.OpenAsync(); + Task resumemilitarybulletopen = ResumeMilitaryBulletConnection.OpenAsync(); + Task resumeeducationopen = ResumeEducationConnection.OpenAsync(); + Task resumeskillopen = ResumeSkillConnection.OpenAsync(); + Task resumelanguageopen = ResumeLanguageConnection.OpenAsync(); + Task resumecertifcationopen = ResumeCertificationConnection.OpenAsync(); + Task resumeprojectopen = ResumeProjectConnection.OpenAsync(); + + // Wait for all the connections to open + await Task.WhenAll(resumeopen, resumeexperienceopen, resumeexperiencebulletopen, resumemilitaryopen, resumemilitarybulletopen, + resumeeducationopen, resumeskillopen, resumelanguageopen, resumecertifcationopen, resumeprojectopen); + + // Setup the commands for the connections + MySqlCommand resumeCommand = new MySqlCommand("SELECT * FROM Resume WHERE ID = @ResumeID;", resumeConnection); + MySqlCommand ResumeExperienceCommand = new MySqlCommand("SELECT * FROM ResumeExperience WHERE ResumeID = @ResumeID;", ResumeExperienceConnection); + MySqlCommand ResumeExperienceBulletCommand = new MySqlCommand("SELECT * FROM ResumeExperienceBullet WHERE ResumeID = @ResumeID;", ResumeExperienceBulletConnection); + MySqlCommand ResumeMilitaryCommand = new MySqlCommand("SELECT * FROM ResumeMilitary WHERE ResumeID = @ResumeID;", ResumeMilitaryConnection); + MySqlCommand ResumeMilitaryBulletCommand = new MySqlCommand("SELECT * FROM ResumeMilitaryBullet WHERE ResumeID = @ResumeID", ResumeMilitaryBulletConnection); + MySqlCommand ResumeEducationCommand = new MySqlCommand("SELECT * FROM ResumeEducation WHERE ResumeID = @ResumeID;", ResumeEducationConnection); + MySqlCommand ResumeSkillCommand = new MySqlCommand("SELECT * FROM ResumeSkill WHERE ResumeID = @ResumeID;", ResumeSkillConnection); + MySqlCommand ResumeLanguageCommand = new MySqlCommand("SELECT * FROM ResumeLanguage WHERE ResumeID = @ResumeID;", ResumeLanguageConnection); + MySqlCommand ResumeCertificationCommand = new MySqlCommand("SELECT * FROM ResumeCertification WHERE ResumeID = @ResumeID;", ResumeCertificationConnection); + MySqlCommand ResumeProjectCommand = new MySqlCommand("SELECT * FROM ResumeProject WHERE ResumeID = @ResumeID;", ResumeProjectConnection); + + // Add parameters to the commands + resumeCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeExperienceCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeExperienceBulletCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeMilitaryCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeMilitaryBulletCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeEducationCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeSkillCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeLanguageCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeCertificationCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + ResumeProjectCommand.Parameters.AddWithValue("@ResumeID", ResumeID); + + // Run the commands + Task ResumeReader = resumeCommand.ExecuteReaderAsync(); + Task ResumeExperienceReader = ResumeExperienceCommand.ExecuteReaderAsync(); + Task ResumeExperienceBulletReader = ResumeExperienceBulletCommand.ExecuteReaderAsync(); + Task ResumeMilitaryReader = ResumeMilitaryCommand.ExecuteReaderAsync(); + Task ResumeMilitaryBulletReader = ResumeMilitaryBulletCommand.ExecuteReaderAsync(); + Task ResumeEducationReader = ResumeEducationCommand.ExecuteReaderAsync(); + Task ResumeSkillReader = ResumeSkillCommand.ExecuteReaderAsync(); + Task ResumeLanguageReader = ResumeLanguageCommand.ExecuteReaderAsync(); + Task ResumeCertificationReader = ResumeCertificationCommand.ExecuteReaderAsync(); + Task ResumeProjectReader = ResumeProjectCommand.ExecuteReaderAsync(); + + // Wait for all the commands to process + await Task.WhenAll(ResumeReader, ResumeExperienceReader, ResumeExperienceBulletReader, ResumeMilitaryReader, ResumeMilitaryBulletReader, + ResumeEducationReader, ResumeSkillReader, ResumeLanguageReader, ResumeCertificationReader, ResumeProjectReader); + + // Get Resume + Resume? resume = await GetResume( await ResumeReader ); + if (resume != null) { + + // Get Resume Parts + ResumeExperience[] experience = await GetResumeExperience(await ResumeExperienceReader); + ResumeExperienceBullet[] experienceBullets = await GetResumeExperienceBullets(await ResumeExperienceBulletReader); + ResumeMilitary? military = await GetResumeMilitary(await ResumeMilitaryReader); + ResumeMilitaryBullet[] militaryBullets = await GetResumeMilitaryBullets(await ResumeMilitaryBulletReader); + ResumeEducation[] education = await GetResumeEducation(await ResumeEducationReader); + ResumeSkill[] skills = await GetResumeSkills(await ResumeSkillReader); + ResumeLanguage[] languages = await GetResumeLanguages(await ResumeLanguageReader); + ResumeCertification[] certs = await GetResumeCertification(await ResumeCertificationReader); + ResumeProject[] projects = await GetResumeProjects(await ResumeProjectReader); + + // Split into grouped lists and add to experience + Dictionary groupedExperienceBullets = experienceBullets.GroupBy(b => b.ResumeExperienceID).ToDictionary(g => g.Key, g => g.ToArray()); + foreach (ResumeExperience cur in experience) { + cur.ExperienceBullets = groupedExperienceBullets[cur.ID]; + } + + // Add the parts to the resume + if (military != null) { + military.MillitaryBullets = militaryBullets; + resume.Millitary = military; + } + resume.Experience = experience; + resume.Educations = education; + resume.Skills = skills; + resume.Languages = languages; + resume.Certification = certs; + resume.Projects = projects; + + return resume; + } + return null; + } + + public async Task SetResume(Resume resume) { + + // Open connections for multi-threaded request + MySqlConnection resumeConnection = GetConnection(); + MySqlConnection ResumeExperienceConnection = GetConnection(); + MySqlConnection ResumeExperienceBulletConnection = GetConnection(); + MySqlConnection ResumeMilitaryConnection = GetConnection(); + MySqlConnection ResumeMilitaryBulletConnection = GetConnection(); + MySqlConnection ResumeEducationConnection = GetConnection(); + MySqlConnection ResumeSkillConnection = GetConnection(); + MySqlConnection ResumeLanguageConnection = GetConnection(); + MySqlConnection ResumeCertificationConnection = GetConnection(); + MySqlConnection ResumeProjectConnection = GetConnection(); + + // Open the connections + Task resumeopen = resumeConnection.OpenAsync(); + Task resumeexperienceopen = ResumeExperienceConnection.OpenAsync(); + Task resumeexperiencebulletopen = ResumeExperienceBulletConnection.OpenAsync(); + Task resumemilitaryopen = ResumeMilitaryConnection.OpenAsync(); + Task resumemilitarybulletopen = ResumeMilitaryBulletConnection.OpenAsync(); + Task resumeeducationopen = ResumeEducationConnection.OpenAsync(); + Task resumeskillopen = ResumeSkillConnection.OpenAsync(); + Task resumelanguageopen = ResumeLanguageConnection.OpenAsync(); + Task resumecertifcationopen = ResumeCertificationConnection.OpenAsync(); + Task resumeprojectopen = ResumeProjectConnection.OpenAsync(); + + // Wait for all the connections to open + await Task.WhenAll(resumeopen, resumeexperienceopen, resumeexperiencebulletopen, resumemilitaryopen, resumemilitarybulletopen, + resumeeducationopen, resumeskillopen, resumelanguageopen, resumecertifcationopen, resumeprojectopen); + + // Get all the experience bullets and run all the updates + List bullets = new List(); + foreach (ResumeExperience cur in resume.Experience) { + foreach (ResumeExperienceBullet bullet in cur.ExperienceBullets) { + bullets.Add(bullet); + } + } + Task ResumeExperienceBulletTask = SetResumeExperienceBullets(ResumeExperienceBulletConnection, bullets.ToArray()); + Task ResumeTask = SetResume(resumeConnection, resume); + Task ResumeExperienceTask = SetResumeExperience(ResumeExperienceConnection, resume.Experience); + Task ResumeMilitaryTask = SetResumeMilitary(ResumeMilitaryConnection, resume.Millitary); + Task ResumeMilitaryBulletTask = SetResumeMilitaryBullets(ResumeMilitaryBulletConnection, resume.Millitary.MillitaryBullets); + Task ResumeEducationTask = SetResumeEducation(ResumeEducationConnection, resume.Educations); + Task ResumeSkllTask = SetResumeSkills(ResumeSkillConnection, resume.Skills); + Task ResumeLanguageTask = SetResumeLanguages(ResumeLanguageConnection, resume.Languages); + Task ResumeCertTask = SetResumeCertification(ResumeCertificationConnection, resume.Certification); + Task ResumeProjectTask = SetResumeProjects(ResumeProjectConnection, resume.Projects); + + // Allow update to finish before closing process + await Task.WhenAll(ResumeTask, ResumeExperienceTask, ResumeExperienceBulletTask, ResumeMilitaryTask, ResumeMilitaryBulletTask, + ResumeEducationTask, ResumeSkllTask, ResumeLanguageTask, ResumeCertTask, ResumeProjectTask); + + } + + public async Task DeleteResume( int ResumeID ) { + using( MySqlConnection connection = GetConnection() ) { + MySqlCommand cmd; + connection.Open(); + + string command = @" + DELETE FROM Resume WHERE ID = @ID; + "; + cmd = new MySqlCommand( command, connection ); + cmd.Parameters.AddWithValue("@ID", ResumeID); + + await cmd.ExecuteNonQueryAsync(); + } + } + + } +} diff --git a/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs new file mode 100644 index 0000000..603bdcc --- /dev/null +++ b/src/Server/Services/DatabaseService/ResumeParts/GetResumeParts.cs @@ -0,0 +1,244 @@ +using BoredCareers.Entities; +using System.Data; +using System.Data.Common; + +namespace BoredCareers.Services.DatabaseService { + public partial class DatabaseService { + + public async Task GetResume(DbDataReader reader) { + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _accountid = reader.GetInt32("AccountID"); + string _name = reader.GetString("Name"); + string _field = reader.GetString("Field"); + string _email = reader.GetString("Email"); + string _phonenumber = reader.GetString("PhoneNumber"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + bool _isactive = reader.GetBoolean("IsActive"); + return new Resume() { + ID = _id, + AccountID = _accountid, + Name = _name, + Field = _field, + Email = _email, + PhoneNumber = _phonenumber, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + IsActive = _isactive + }; + } + return null; + } + + public async Task GetResumeExperienceBullets(DbDataReader reader) { + List experienceBullets = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + int _experienceid = reader.GetInt32("ResumeExperienceID"); + string _jobfunction = reader.GetString("JobFunction"); + experienceBullets.Add(new ResumeExperienceBullet() { + ID = _id, + ResumeID = _resumeid, + ResumeExperienceID = _experienceid, + JobFunction = _jobfunction + }); + } + return experienceBullets.ToArray(); + } + + public async Task GetResumeExperience(DbDataReader reader) { + List experience = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _jobtitle = reader.GetString("JobTitle"); + string _company = reader.GetString("Company"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + DateTime _datestarted = reader.GetDateTime("DateStarted"); + bool _stillempoyed = reader.GetBoolean("StillEmployed"); + DateTime _dateended = reader.GetDateTime("DateEnded"); + experience.Add(new ResumeExperience() { + ID = _id, + ResumeID = _resumeid, + JobTitle = _jobtitle, + Company = _company, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + DateStarted = _datestarted, + StillEmployed = _stillempoyed, + DateEnded = _dateended, + }); + } + return experience.ToArray(); + } + + public async Task GetResumeMilitaryBullets(DbDataReader reader) { + List militaryBullets = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + int _experienceid = reader.GetInt32("ResumeMilitaryID"); + string _achievement = reader.GetString("Achievement"); + string _description = reader.GetString("Description"); + militaryBullets.Add(new ResumeMilitaryBullet() { + ID = _id, + ResumeID = _resumeid, + ResumeMilitaryID = _experienceid, + Achievement = _achievement, + Description = _description + }); + } + return militaryBullets.ToArray(); + } + + public async Task GetResumeMilitary(DbDataReader reader) { + ResumeMilitary? military = null; + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _country = reader.GetString("Country"); + string _rank = reader.GetString("Rank"); + DateTime _datestarted = reader.GetDateTime("DateStarted"); + bool _stillServing = reader.GetBoolean("StillServing"); + DateTime _dateended = reader.GetDateTime("DateEnded"); + military = new ResumeMilitary() { + ID = _id, + ResumeID = _resumeid, + Country = _country, + Rank = _rank, + DateStarted = _datestarted, + StillServing = _stillServing, + DateEnded = _dateended, + }; + } + return military; + } + + public async Task GetResumeEducation(DbDataReader reader) { + List? education = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _degreetype = reader.GetString("DegreeType"); + string _degreefield = reader.GetString("DegreeField"); + string _school = reader.GetString("School"); + string _postalcode = reader.GetString("PostalCode"); + string _country = reader.GetString("Country"); + string _state = reader.GetString("StateOrRegion"); + string _city = reader.GetString("City"); + DateTime _datestarted = reader.GetDateTime("DateStarted"); + bool _stillstudying = reader.GetBoolean("StillStudying"); + DateTime _dateended = reader.GetDateTime("DateEnded"); + education.Add(new ResumeEducation { + ID = _id, + ResumeID = _resumeid, + DegreeType = _degreetype, + DegreeField = _degreefield, + School = _school, + PostalCode = _postalcode, + Country = _country, + StateOrRegion = _state, + City = _city, + DateStarted = _datestarted, + StillStudying = _stillstudying, + DateEnded = _dateended + }); + } + return education.ToArray(); + } + + public async Task GetResumeSkills(DbDataReader reader) { + List skills = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _name = reader.GetString("Name"); + string _description = reader.GetString("Description"); + skills.Add( new ResumeSkill { + ID = _id, + ResumeID = _resumeid, + Name = _name, + Description = _description + } ); + } + return skills.ToArray(); + } + + public async Task GetResumeLanguages(DbDataReader reader) { + List? languages = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _language = reader.GetString("Language"); + string _proficiency = reader.GetString("Proficiency"); + languages.Add( new ResumeLanguage { + ID = _id, + ResumeID = _resumeid, + Language = _language, + Proficiency = _proficiency + } ); + } + return languages.ToArray(); + } + + public async Task GetResumeCertification(DbDataReader reader) { + List certs = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _name = reader.GetString("Name"); + string _url = reader.GetString("VerificationURL"); + string _description = reader.GetString("Description"); + certs.Add( new ResumeCertification { + ID = _id, + ResumeID = _resumeid, + Name = _name, + VerificationURL = _url, + Description = _description + } ); + } + return certs.ToArray(); + } + + public async Task GetResumeProjects(DbDataReader reader) { + List? projects = new List(); + while (await reader.ReadAsync()) { + if (reader == null) { break; } + int _id = reader.GetInt32("ID"); + int _resumeid = reader.GetInt32("ResumeID"); + string _name = reader.GetString("Name"); + string _url = reader.GetString("URL"); + string _description = reader.GetString("Description"); + projects.Add( new ResumeProject { + ID = _id, + ResumeID = _resumeid, + Name = _name, + URL = _url, + Description = _description + } ); + } + return projects.ToArray(); + } + + } +} diff --git a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs new file mode 100644 index 0000000..089f385 --- /dev/null +++ b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs @@ -0,0 +1,287 @@ +using BoredCareers.Entities; +using MySql.Data.MySqlClient; + +namespace BoredCareers.Services.DatabaseService { + public partial class DatabaseService { + + public async Task SetResume(MySqlConnection connection, Resume resume) { + string command = @" + INSERT INTO Resume + (ID,AccountID,Name,Field,Email,PhoneNumber,PostalCode,Country,StateOrRegion,City,IsActive) + VALUES + (@ID,@AccountID,@Name,@Field,@Email,@PhoneNumber,@PostalCode,@Country,@StateOrRegion,@City,@IsActive); + ON DUPLICATE KEY UPDATE + AccountID = @AccountID, + Name = @Name, + Field = @Field, + Email = @Email, + PhoneNumber = @PhoneNumber, + PostalCode = @PostalCode, + Country = @Country, + StateOrRegion = @StateOrRegion, + City = @City, + IsActive = @IsActive; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", resume.ID); + cmd.Parameters.AddWithValue("@AccountID", resume.AccountID); + cmd.Parameters.AddWithValue("@Name", resume.Name); + cmd.Parameters.AddWithValue("@Field", resume.Field); + cmd.Parameters.AddWithValue("@Email", resume.Email); + cmd.Parameters.AddWithValue("@PhoneNumber", resume.PhoneNumber); + cmd.Parameters.AddWithValue("@PostalCode", resume.PostalCode); + cmd.Parameters.AddWithValue("@Country", resume.Country); + cmd.Parameters.AddWithValue("@StateOrRegion", resume.StateOrRegion); + cmd.Parameters.AddWithValue("@City", resume.City); + cmd.Parameters.AddWithValue("@IsActive", resume.IsActive); + + await cmd.ExecuteNonQueryAsync(); + } + + public async Task SetResumeExperienceBullets(MySqlConnection connection, ResumeExperienceBullet[] bullets) { + foreach (ResumeExperienceBullet cur in bullets) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,ResumeExperienceID,JobFunction) + VALUES + (@ID,@ResumeID,@ResumeExperienceID,@JobFunction); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + ResumeExperienceID = @ResumeExperienceID, + JobFunction = @JobFunction; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@ResumeExperienceID", cur.ResumeExperienceID); + cmd.Parameters.AddWithValue("@JobFunction", cur.JobFunction); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeExperience(MySqlConnection connection, ResumeExperience[] experiences) { + foreach (ResumeExperience cur in experiences) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,JobTitle,Company,PostalCode,Country,StateOrRegion,City,DateStarted,StillEmployed,DateEnded) + VALUES + (@ID,@ResumeID,@JobTitle,@Company,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillEmployed,@DateEnded); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + JobTitle = @JobTitle, + Company = @Company, + PostalCode = @PostalCode, + Country = @Country, + StateOrRegion = @StateOrRegion, + City = @City, + DateStarted = @DateStarted, + StillEmployed = @StillEmployed, + DateEnded = @DateEnded; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@JobTitle", cur.JobTitle); + cmd.Parameters.AddWithValue("@Company", cur.Company); + cmd.Parameters.AddWithValue("@PostalCode", cur.PostalCode); + cmd.Parameters.AddWithValue("@DateStarted", cur.DateStarted.ToUniversalTime()); + cmd.Parameters.AddWithValue("@StillEmployed", cur.StillEmployed); + cmd.Parameters.AddWithValue("@DateEnded", cur.DateEnded.ToUniversalTime()); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeMilitaryBullets(MySqlConnection connection, ResumeMilitaryBullet[] bullets) { + foreach (ResumeMilitaryBullet cur in bullets) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,ResumeMilitaryID,Achievement) + VALUES + (@ID,@ResumeID,@ResumeMilitaryID,@Achievement); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + ResumeMilitaryID = @ResumeMilitaryID, + Achievement = @Achievement, + Description = @Description; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@ResumeMilitaryID", cur.ResumeMilitaryID); + cmd.Parameters.AddWithValue("@Achievement", cur.Achievement); + cmd.Parameters.AddWithValue("@Description", cur.Description); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeMilitary(MySqlConnection connection, ResumeMilitary military) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,Country,Rank,DateStarted,StillServing,DateEnded) + VALUES + (@ID,@ResumeID,@Country,@Rank,@DateStarted,@StillServing,@DateEnded); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + Country = @Country, + Rank = @Rank, + DateStarted = @DateStarted, + StillServing = @StillServing, + DateEnded = @DateEnded; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", military.ID); + cmd.Parameters.AddWithValue("@ResumeID", military.ResumeID); + cmd.Parameters.AddWithValue("@Country", military.Country); + cmd.Parameters.AddWithValue("@Rank", military.Rank); + cmd.Parameters.AddWithValue("@DateStarted", military.DateStarted.ToUniversalTime()); + cmd.Parameters.AddWithValue("@StillServing", military.StillServing); + cmd.Parameters.AddWithValue("@DateEnded", military.DateEnded.ToUniversalTime()); + + await cmd.ExecuteNonQueryAsync(); + } + + public async Task SetResumeEducation(MySqlConnection connection, ResumeEducation[] educations) { + foreach (ResumeEducation cur in educations) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,DegreeType,DegreeField,School,PostalCode,Country,StateOrRegion,City,DateStarted,StillStudying,DateEnded) + VALUES + (@ID,@ResumeID,@DegreeType,@DegreeField,@School,@PostalCode,@Country,@StateOrRegion,@City,@DateStarted,@StillStudying,@DateEnded); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + DegreeType = @DegreeType, + DegreeField = @DegreeField, + School = @School, + PostalCode = @PostalCode, + Country = @Country, + StateOrRegion = @StateOrRegion, + City = @City, + DateStarted = @DateStarted, + StillStudying = @StillStudying, + DateEnded = @DateEnded; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@DegreeType", cur.DegreeType); + cmd.Parameters.AddWithValue("@DegreeField", cur.DegreeField); + cmd.Parameters.AddWithValue("@School", cur.School); + cmd.Parameters.AddWithValue("@PostalCode", cur.PostalCode); + cmd.Parameters.AddWithValue("@Country", cur.Country); + cmd.Parameters.AddWithValue("@StateOrRegion", cur.StateOrRegion); + cmd.Parameters.AddWithValue("@City", cur.City); + cmd.Parameters.AddWithValue("@DateStarted", cur.DateStarted.ToUniversalTime()); + cmd.Parameters.AddWithValue("@StillStudying", cur.StillStudying); + cmd.Parameters.AddWithValue("@DateEnded", cur.DateEnded.ToUniversalTime()); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeSkills(MySqlConnection connection, ResumeSkill[] skills) { + foreach (ResumeSkill cur in skills) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,Name,Description) + VALUES + (@ID,@ResumeID,@Name,@Description); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + Name = @Name, + Description = @Description; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@Name", cur.Name); + cmd.Parameters.AddWithValue("@Description", cur.Description); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeLanguages(MySqlConnection connection, ResumeLanguage[] languages) { + foreach (ResumeLanguage cur in languages) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,Language,Proficiency) + VALUES + (@ID,@ResumeID,@Language,@Proficiency); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + Language = @Language, + Proficiency = @Proficiency; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@Language", cur.Language); + cmd.Parameters.AddWithValue("@Proficiency", cur.Proficiency); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeCertification(MySqlConnection connection, ResumeCertification[] certifications) { + foreach (ResumeCertification cur in certifications) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,Name,VerificationURL,Description) + VALUES + (@ID,@ResumeID,@Name,@VerificationURL,@Description); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + Name = @DegreeNameType, + VerificationURL = @VerificationURL, + Description = @Description; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@Name", cur.Name); + cmd.Parameters.AddWithValue("@VerificationURL", cur.VerificationURL); + cmd.Parameters.AddWithValue("@Description", cur.Description); + + await cmd.ExecuteNonQueryAsync(); + } + } + + public async Task SetResumeProjects(MySqlConnection connection, ResumeProject[] projects) { + foreach (ResumeProject cur in projects) { + string command = @" + INSERT INTO Resume + (ID,ResumeID,Name,URL,Description) + VALUES + (@ID,@ResumeID,@Name,@URL,@Description); + ON DUPLICATE KEY UPDATE + ResumeID = @ResumeID, + Name = @Name, + URL = @URL, + Description = @Description; + "; + + MySqlCommand cmd = new MySqlCommand(command, connection); + cmd.Parameters.AddWithValue("@ID", cur.ID); + cmd.Parameters.AddWithValue("@ResumeID", cur.ResumeID); + cmd.Parameters.AddWithValue("@Name", cur.Name); + cmd.Parameters.AddWithValue("@URL", cur.URL); + cmd.Parameters.AddWithValue("@Description", cur.Description); + + await cmd.ExecuteNonQueryAsync(); + } + } + + } +}