From 4b5b1492d93acb9ec0058a10a62f9ab08cf7614c Mon Sep 17 00:00:00 2001 From: Matthew Date: Thu, 14 Nov 2024 17:37:14 +0000 Subject: [PATCH] Get patient dashboard connected to DB and update address functionality working --- Controllers/AuthController.cs | 10 ++-- Controllers/DashboardController.cs | 44 ++++++++++------- Extensions/HttpExtensions.cs | 5 ++ Middleware/AuthMiddleware.cs | 5 +- Models/AuthModels.cs | 8 ++++ Models/DashboardModels.cs | 10 +++- Program.cs | 2 + Services/AuthService.cs | 4 +- Services/DatabaseService.cs | 54 +++++++++++++++++++++ Services/PatientService.cs | 69 ++++++++++++++++++++++++++ Views/Dashboard/Patient.cshtml | 13 +++-- Views/Dashboard/UpdateAddress.cshtml | 72 ++++++++++++++++++++++++++++ Views/Shared/_Layout.cshtml | 2 +- 13 files changed, 269 insertions(+), 29 deletions(-) create mode 100644 Services/PatientService.cs create mode 100644 Views/Dashboard/UpdateAddress.cshtml diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index 9eebf64..c4d28aa 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -11,11 +11,15 @@ public class AuthController(ILogger logger, AuthService authServ { public IActionResult Login() { + TempData["hideLogout"] = true; + return View(); } public IActionResult Register() { + TempData["hideLogout"] = true; + return View(); } @@ -38,12 +42,11 @@ public IActionResult Logout() [HttpPost] public IActionResult Login([FromForm] LoginDetails loginDetails) { - TempData["hideLogout"] = true; - var loginResult = authService.AttemptLogin(loginDetails); if (!loginResult.success) { + TempData["hideLogout"] = true; TempData["errorMsg"] = "Invalid email or password"; return View(); @@ -57,12 +60,11 @@ public IActionResult Login([FromForm] LoginDetails loginDetails) [HttpPost] public IActionResult Register([FromForm] RegisterDetails registerDetails) { - TempData["hideLogout"] = true; - var createAccountResult = authService.AttemptCreateAccount(registerDetails); if (!createAccountResult.success) { + TempData["hideLogout"] = true; TempData["errorMsg"] = "Could not create account with that email."; return View(); diff --git a/Controllers/DashboardController.cs b/Controllers/DashboardController.cs index 2ad5bba..81178fe 100644 --- a/Controllers/DashboardController.cs +++ b/Controllers/DashboardController.cs @@ -1,29 +1,39 @@ using Microsoft.AspNetCore.Mvc; +using SecureDesignProject.Extensions; using SecureDesignProject.Models; +using SecureDesignProject.Services; namespace SecureDesignProject.Controllers; -public class DashboardController : Controller +public class DashboardController(PatientService patientService) : Controller { public IActionResult Patient() { - var model = new PatientInfo + var patient = patientService.GetPatientInfoByAccountId(HttpContext.GetAccountId()); + + if (patient == null) return RedirectToAction("Error", "Home"); + + + return View(patient); + } + + public IActionResult UpdateAddress() + { + var address = patientService.GetAddressByAccountId(HttpContext.GetAccountId()); + return View(address); + } + + [HttpPost] + public IActionResult UpdateAddress(Address address) + { + var success = patientService.AttemptUpdateAddress(HttpContext.GetAccountId(), address); + + if (!success) { - AssignedCaregivers = ["Dr Steve London", "Dr Bruce Potter"], - PatientName = "John Doe", - Address = "123 Main Street\nLondon\nEC5 8BC", - Appointments = [ - new AppointmentInfo - { - Caregiver = "Dr Steve London", - Patient = "John Doe", - AppointmentTime = DateTime.Now.ToString("dd/MM/yyyy HH:mm"), - AppointmentDuration = "30", - Notes = "Notes for Dr Steve London. And Dr Bruce Potter is the same time as the day. ALSO IT is the same time as the day. The day is the same time as the day. This is very strange auto complete." - } - ] - }; + TempData["errorMsg"] = "Failed to update address."; + return View(address); + } - return View(model); + return RedirectToAction("Patient"); } } \ No newline at end of file diff --git a/Extensions/HttpExtensions.cs b/Extensions/HttpExtensions.cs index f46e8a3..04a20fb 100644 --- a/Extensions/HttpExtensions.cs +++ b/Extensions/HttpExtensions.cs @@ -18,4 +18,9 @@ public static void SetSessionKeyCookie(this HttpResponse response, byte[] sessio var cookie = request.Cookies["session_key"]; return cookie == null ? null : Convert.FromHexString(cookie!); } + + public static Guid GetAccountId(this HttpContext context) + { + return context.Items["accountId"] as Guid? ?? Guid.Empty; + } } \ No newline at end of file diff --git a/Middleware/AuthMiddleware.cs b/Middleware/AuthMiddleware.cs index b8d9ceb..d934177 100644 --- a/Middleware/AuthMiddleware.cs +++ b/Middleware/AuthMiddleware.cs @@ -24,11 +24,14 @@ public async Task InvokeAsync(HttpContext context) return; } - if (!authService.IsValidSession(sessionKey!)) + var result = authService.ValidateSession(sessionKey!); + if (!result.isValid) { context.Response.Redirect("/auth/login"); return; } + + context.Items["accountId"] = result.accountId; // Call the next delegate/middleware in the pipeline. await next(context); diff --git a/Models/AuthModels.cs b/Models/AuthModels.cs index b6ab67d..c6b4b63 100644 --- a/Models/AuthModels.cs +++ b/Models/AuthModels.cs @@ -62,6 +62,14 @@ public record Patient public string? Address { get; init; } } +public record Caregiver +{ + public Guid PatientId { get; init; } = Guid.NewGuid(); + public Guid AccountId { get; init; } + public string FirstName { get; init; } = ""; + public string LastName { get; init; } = ""; +} + public record Session { public Guid SessionId { get; init; } diff --git a/Models/DashboardModels.cs b/Models/DashboardModels.cs index 6b8a87d..71c8d9d 100644 --- a/Models/DashboardModels.cs +++ b/Models/DashboardModels.cs @@ -7,7 +7,7 @@ public record PatientInfo public string[] AssignedCaregivers { get; init; } = []; public string PatientName { get; init; } - public string? Address { get; init; } + public Address? Address { get; init; } public AppointmentInfo[] Appointments { get; init; } = []; } @@ -20,4 +20,12 @@ public record AppointmentInfo public string AppointmentDuration { get; init; } // in minutes public string Notes { get; init; } +} + +public record Address +{ + [Required] public string Line1 { get; init; } = ""; + public string Line2 { get; init; } = ""; + [Required] public string City { get; init; } = ""; + [Required] public string Postcode { get; init; } = ""; } \ No newline at end of file diff --git a/Program.cs b/Program.cs index 41840d3..5da5aab 100644 --- a/Program.cs +++ b/Program.cs @@ -1,4 +1,5 @@ using SecureDesignProject.Middleware; +using SecureDesignProject.Models; using SecureDesignProject.Services; var builder = WebApplication.CreateBuilder(args); @@ -7,6 +8,7 @@ builder.Services.AddControllersWithViews(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); var app = builder.Build(); diff --git a/Services/AuthService.cs b/Services/AuthService.cs index 05470fc..cf7be56 100644 --- a/Services/AuthService.cs +++ b/Services/AuthService.cs @@ -32,11 +32,11 @@ public class AuthService(DatabaseService dbService) return (true, newSession.SessionKey); } - public bool IsValidSession(byte[] key) + public (bool isValid, Guid accountId) ValidateSession(byte[] key) { var session = dbService.GetSessionByKey(key); - return session != null; + return (session != null, session?.AccountId ?? Guid.Empty); } public (bool success, byte[] SessionKey) AttemptCreateAccount(RegisterDetails registerDetails) diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs index a310719..4cc4fb2 100644 --- a/Services/DatabaseService.cs +++ b/Services/DatabaseService.cs @@ -35,6 +35,20 @@ UPDATE Sessions return session; } + + public Patient? UpdatePatient(Patient patient) + { + using var db = new SqlConnection(ConnectionString); + + db.Execute(""" + UPDATE Patients + SET FirstName=@firstName, LastName=@lastName, Address=@address + WHERE PatientId = @patientId + """, + patient); + + return patient; + } public Account InsertAccount(Account account) { @@ -86,4 +100,44 @@ FROM Sessions """, new {sessionKey}); } + + public Patient? GetPatientByAccountId(Guid accountId) + { + using var db = new SqlConnection(ConnectionString); + + return db.QuerySingleOrDefault(""" + SELECT * + FROM Patients + WHERE AccountId = @accountId + """, + new {accountId}); + } + public Caregiver? GetCaregiverByAccountId(Guid accountId) + { + using var db = new SqlConnection(ConnectionString); + + return db.QuerySingleOrDefault(""" + SELECT * + FROM Caregivers + WHERE AccountId = @accountId + """, + new {accountId}); + } + + public IEnumerable GetCaregiversByAssignedPatient(Guid patientId) + { + using var db = new SqlConnection(ConnectionString); + + return db.Query(""" + SELECT * + FROM Caregivers + WHERE CaregiverId IN ( + SELECT Caregiver_Patients.CaregiverId + FROM Caregivers + INNER JOIN Caregiver_Patients ON Caregivers.CaregiverId = Caregiver_Patients.CaregiverId + WHERE Caregiver_Patients.PatientId = @patientId AND CurrentlyAssigned=1 + ) + """, + new {patientId}); + } } \ No newline at end of file diff --git a/Services/PatientService.cs b/Services/PatientService.cs new file mode 100644 index 0000000..522bf3f --- /dev/null +++ b/Services/PatientService.cs @@ -0,0 +1,69 @@ +using SecureDesignProject.Models; + +namespace SecureDesignProject.Services; + +public class PatientService(DatabaseService dbService) +{ + public PatientInfo? GetPatientInfoByAccountId(Guid accountId) + { + var patient = dbService.GetPatientByAccountId(accountId); + if (patient == null) return null; + + var caregivers = dbService + .GetCaregiversByAssignedPatient(patient.PatientId) + .Select(x => x.FirstName + " " + x.LastName) + .ToArray(); + + + var splitAddress = patient.Address?.Split('\n'); + + return new PatientInfo + { + PatientName = patient.FirstName + " " + patient.LastName, + Address = splitAddress != null ? + new Address + { + Line1 = splitAddress[0], + Line2 = splitAddress[1], + City = splitAddress[2], + Postcode = splitAddress[3], + } : null, + AssignedCaregivers = caregivers, + Appointments = [] //TODO: implement appointments + }; + } + + public Address? GetAddressByAccountId(Guid accountId) + { + var patient = dbService.GetPatientByAccountId(accountId); + + if (patient == null) return null; + + var splitAddress = patient.Address?.Split('\n'); + + if (splitAddress == null) return new Address(); + + return new Address + { + Line1 = splitAddress[0], + Line2 = splitAddress[1], + City = splitAddress[2], + Postcode = splitAddress[3], + }; + } + + public bool AttemptUpdateAddress(Guid accountId, Address address) + { + var patient = dbService.GetPatientByAccountId(accountId); + if (patient == null) return false; + + var addressString = address.Line1 + "\n" + address.Line2 + "\n" + address.City + "\n" + address.Postcode; + + dbService.UpdatePatient(patient with + { + Address = addressString + }); + + return true; + } +} \ No newline at end of file diff --git a/Views/Dashboard/Patient.cshtml b/Views/Dashboard/Patient.cshtml index e600a83..a9a708c 100644 --- a/Views/Dashboard/Patient.cshtml +++ b/Views/Dashboard/Patient.cshtml @@ -27,13 +27,16 @@

Address:

@if (Model.Address != null) { -

@Model.Address

- +

@Model.Address.Line1

+

@Model.Address.Line2

+

@Model.Address.City

+

@Model.Address.Postcode

+ } else {

You have not yet provided your address.

- + } @@ -48,6 +51,10 @@

@appointment.Notes

} + @if (Model.Appointments.Length == 0) + { +

You don't currently have any scheduled appointments.

+ } diff --git a/Views/Dashboard/UpdateAddress.cshtml b/Views/Dashboard/UpdateAddress.cshtml new file mode 100644 index 0000000..0459f66 --- /dev/null +++ b/Views/Dashboard/UpdateAddress.cshtml @@ -0,0 +1,72 @@ +@model SecureDesignProject.Models.Address + +

Update Address

+
+ + +@using (Html.BeginForm("UpdateAddress", "Dashboard", FormMethod.Post)) +{ +
+ +

Enter your address:

+ + + @Html.ValidationSummary(true, "", new { @class = "text-danger" }) + + @Html.TextBoxFor(m => m.Line1, new + { + id = "line1-box", + type="text", + placeholder="Line 1", + @class = "form-control m-3 w-auto" + }) + @Html.ValidationMessageFor(model => model.Line1, default, new + { + @class = "m-3 text-danger" + }) + + @Html.TextBoxFor(m => m.Line2,new + { + id = "line2-box", + type="text", + placeholder="Line 2", + @class = "form-control m-3 w-auto" + }) + @Html.ValidationMessageFor(model => model.Line2, default, new + { + @class = "m-3 text-danger" + }) + + @Html.TextBoxFor(m => m.City,new + { + id = "city-box", + type="text", + placeholder="City", + @class = "form-control m-3 w-auto" + }) + @Html.ValidationMessageFor(model => model.City, default, new + { + @class = "m-3 text-danger" + }) + + @Html.TextBoxFor(m => m.Postcode,new + { + id = "postcode-box", + type="text", + placeholder="Postcode", + @class = "form-control m-3 w-auto" + }) + @Html.ValidationMessageFor(model => model.Postcode, default, new + { + @class = "m-3 text-danger" + }) +
+ + + +} + +@if (TempData["errorMsg"] != null) +{ + +} diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 117b98b..76698af 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -29,7 +29,7 @@