From 9e13317ca393df6f3b82bf00c1c391904f23f782 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Tue, 15 Jul 2025 21:06:16 -0700 Subject: [PATCH] Update API to follow REST --- .../Controllers/AuthenticationController.cs | 93 ++++++++++--------- src/Server/Controllers/CompanyController.cs | 15 ++- .../Controllers/JobListingController.cs | 36 ++++--- src/Server/Controllers/PaymentController.cs | 12 +-- src/Server/Controllers/ResumeController.cs | 41 ++++---- src/Server/Program.cs | 8 +- .../ResumeParts/SetResumeParts.cs | 2 - 7 files changed, 95 insertions(+), 112 deletions(-) diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 9b37afd..4a532da 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -5,6 +5,8 @@ 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] @@ -26,7 +28,7 @@ namespace BoredCareers.Controllers { if (test.EmailVerified == true) { if (test.FailedPasswordLock) { if (test.CurrentPasswordAttempts >= test.PasswordAttempts) { - return new Account() { ID = -1, UserName = "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)) { @@ -47,21 +49,20 @@ namespace BoredCareers.Controllers { } ); return test; - } - else { + } else { test.CurrentPasswordAttempts += 1; await _databaseService.SetAccount(test); - return new Account() { ID = -1, UserName = "Wrong Password" }; + return Ok(new Account() { ID = -1, UserName = "Wrong Password" }); } - } - else { + } else { await SendVerify(test.UserName); - return new Account() { ID = -1, UserName = "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() { ID = -1, UserName = "User doesn't exist" }; + return NotFound("Account Not Found"); } catch (Exception ex) { - return new Account() { ID = -1, UserName = ex.Message }; + Console.WriteLine("Login Error: " + ex.Message); + return NotFound(); } } @@ -71,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() { ID = -1, UserName = "Unknown Error" }; + return NotFound("Unable to create the account"); + } else { + return NotFound("Email is already in use"); } - else { - return new Account() { ID = -1, UserName = "Email is already in use" }; - } - } - else { - return new Account() { ID = -1, UserName = "UserName is taken" }; + } else { + return NotFound("UserName is taken"); } } catch (Exception ex) { - Console.WriteLine("Error: " + ex.Message); - return new Account() { ID = -1, UserName = 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(); @@ -109,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(); } } @@ -127,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")] @@ -267,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/CompanyController.cs b/src/Server/Controllers/CompanyController.cs index 799f4f0..cb644a2 100644 --- a/src/Server/Controllers/CompanyController.cs +++ b/src/Server/Controllers/CompanyController.cs @@ -5,16 +5,15 @@ using System.Web.Http; namespace BoredCareers.Controllers { [ApiController] - [Route("api/company/")] + [Route("api/company")] public class CompanyController : MistoxControllerBase { public CompanyController(DatabaseService db) : base(db) {} - [Route("get")] - [HttpPost] - public async Task GetCompany([FromForm] int companyID) { + [HttpGet] + public async Task GetCompany(int CompanyID) { if (isLoggedIn()) { - Company? company = await _databaseService.GetCompany(companyID); + Company? company = await _databaseService.GetCompany(CompanyID); if (company != null) { return Ok(company); } @@ -22,7 +21,6 @@ namespace BoredCareers.Controllers { return NotFound(); } - [Route("set")] [HttpPost] public async Task SetCompany([FromBody] Company company) { if (isLoggedIn()) { @@ -34,9 +32,8 @@ namespace BoredCareers.Controllers { return NotFound(); } - [Route("delete")] - [HttpPost] - public async Task DeleteCompany([FromForm] int CompanyID) { + [HttpDelete] + public async Task DeleteCompany(int CompanyID) { if (isLoggedIn()) { if (await isLoggedInUserEmployeeOf(CompanyID)) { await _databaseService.DeleteCompany(CompanyID); diff --git a/src/Server/Controllers/JobListingController.cs b/src/Server/Controllers/JobListingController.cs index 805d12a..495fb0b 100644 --- a/src/Server/Controllers/JobListingController.cs +++ b/src/Server/Controllers/JobListingController.cs @@ -5,42 +5,38 @@ using System.Web.Http; namespace BoredCareers.Controllers { [ApiController] - [Route("api/joblisting/")] + [Route("api/joblisting")] public class JobListingController : MistoxControllerBase { public JobListingController(DatabaseService db) : base(db) {} - [Route("getpage")] - [HttpPost] - public async Task GetJobListings([FromForm] int page) { - JobListing[] jobListings = await _databaseService.GetJobListingPage(page, 25); // 10 items per page - return Ok(jobListings); - } - - [Route("get")] - [HttpPost] - public async Task GetJobListing([FromForm] int JobListingID) { - JobListing? jobListing = await _databaseService.GetJobListing(JobListingID); - if (jobListing == null) { + [HttpGet("{JobListingID}")] + public async Task GetJobListing([FromRoute] int JobListingID) { + var jobListing = await _databaseService.GetJobListing(JobListingID); + if (jobListing != null) { return Ok(jobListing); } return NotFound(); } - [Route("set")] + [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) { + public async Task SetJobListing([FromBody] JobListing JobListing) { if (isLoggedIn()) { - if (await isLoggedInUserEmployeeOf(jobListing.CompanyID)) { - await _databaseService.SetJobListing(jobListing); + if (await isLoggedInUserEmployeeOf(JobListing.CompanyID)) { + await _databaseService.SetJobListing(JobListing); } } return NotFound(); } - [Route("delete")] - [HttpPost] - public async Task DeleteJobListing([FromForm] int JobListingID) { + [HttpDelete] + public async Task DeleteJobListing(int JobListingID) { if (isLoggedIn()) { JobListing? jobListing = await _databaseService.GetJobListing(JobListingID); if (jobListing != null) { diff --git a/src/Server/Controllers/PaymentController.cs b/src/Server/Controllers/PaymentController.cs index 0d9fdbf..31e0537 100755 --- a/src/Server/Controllers/PaymentController.cs +++ b/src/Server/Controllers/PaymentController.cs @@ -4,7 +4,7 @@ using BoredCareers.Services.DatabaseService; namespace BoredCareers.Controllers { [ApiController] - [Route("api/payment/")] + [Route("api/payment")] public class PaymentController : MistoxControllerBase { IPayment _paymentService; @@ -19,17 +19,11 @@ namespace BoredCareers.Controllers { // Add new payment plugins here } - [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/ResumeController.cs b/src/Server/Controllers/ResumeController.cs index 01d6c67..65b9099 100644 --- a/src/Server/Controllers/ResumeController.cs +++ b/src/Server/Controllers/ResumeController.cs @@ -5,33 +5,28 @@ using System.Web.Http; namespace BoredCareers.Controllers { [ApiController] - [Route("api/resume/")] + [Route("api/resume")] public class ResumeController : MistoxControllerBase { public ResumeController(DatabaseService db) : base(db) {} - [Route("getall")] - [HttpPost] - public async Task GetResumes() { - if (isLoggedIn()) { - int accountID = getLoggedInUserID(); - Resume[] resumes = await _databaseService.GetResumes(accountID); - return Ok(resumes); + [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(); } - [Route("get")] - [HttpPost] - public async Task GetResume([FromForm] int ResumeID) { - Resume? resume = await _databaseService.GetResume(ResumeID); - if (resume == null) { - return Ok(resume); - } - return NotFound(); - } - - [Route("set")] [HttpPost] public async Task SetResume([FromBody] Resume resume) { if (isLoggedIn()) { @@ -44,9 +39,8 @@ namespace BoredCareers.Controllers { return NotFound(); } - [Route("delete")] - [HttpPost] - public async Task DeleteResume([FromForm] int ResumeID) { + [HttpDelete] + public async Task DeleteResume(int ResumeID) { if (isLoggedIn()){ int accountID = getLoggedInUserID(); Resume? resume = await _databaseService.GetResume(ResumeID); @@ -59,5 +53,4 @@ namespace BoredCareers.Controllers { } } - -} +} \ No newline at end of file diff --git a/src/Server/Program.cs b/src/Server/Program.cs index 1df3be9..bed8db4 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -3,7 +3,6 @@ using BoredCareers.Controllers.Payment; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; using System.Threading.RateLimiting; -using Microsoft.AspNetCore.RateLimiting; using Stripe; using System.Security.Claims; @@ -99,10 +98,9 @@ builder.Services.AddCors(o => o.AddDefaultPolicy(builder => { builder.Services.AddRateLimiter(options => { options.AddPolicy("PerUserPolicy", httpContext => { - // Identify the user (assumes authenticated user with NameIdentifier claim) - var userId = httpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value - ?? httpContext.User.Identity?.Name - ?? httpContext.Connection.RemoteIpAddress?.ToString(); + 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 diff --git a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs index d82992a..089f385 100644 --- a/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs +++ b/src/Server/Services/DatabaseService/ResumeParts/SetResumeParts.cs @@ -1,8 +1,6 @@ using BoredCareers.Entities; using MySql.Data.MySqlClient; -// TODO: Fix Data type mangling. Such As DateTime - namespace BoredCareers.Services.DatabaseService { public partial class DatabaseService {