From fbcebd47d9779d7e65486237cac448b14ffde9ae Mon Sep 17 00:00:00 2001 From: Astrian Zheng Date: Thu, 19 Oct 2023 10:31:41 +1100 Subject: [PATCH] Upload images --- .../Controllers/AppointmentsController.cs | 201 +++++++++++++++--- FIT5032-Assignment/FIT5032-Assignment.csproj | 3 +- .../Views/Appointments/Index.cshtml | 2 +- .../Views/Appointments/UploadImage.cshtml | 28 +++ .../Views/Home/ImageUpload.cshtml | 35 +-- 5 files changed, 212 insertions(+), 57 deletions(-) create mode 100644 FIT5032-Assignment/Views/Appointments/UploadImage.cshtml diff --git a/FIT5032-Assignment/Controllers/AppointmentsController.cs b/FIT5032-Assignment/Controllers/AppointmentsController.cs index a639d4d..e4f6d1d 100644 --- a/FIT5032-Assignment/Controllers/AppointmentsController.cs +++ b/FIT5032-Assignment/Controllers/AppointmentsController.cs @@ -16,9 +16,24 @@ using Org.BouncyCastle.Security; using System.IO; using System.Security.Cryptography; using System.Globalization; +using RestSharp.Authenticators; +using RestSharp; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Newtonsoft.Json; namespace FIT5032_Assignment.Controllers { public class AppointmentsController : Controller { + public class PassageUserAPI { + public PassageUserEntity User { get; set; } + } + + public class PassageUserEntity { + public string CreatedAt { get; set; } + public string Email { get; set; } + public bool EmailVerified { get; set; } + } + private Database1Entities db = new Database1Entities(); // Login check @@ -331,39 +346,177 @@ namespace FIT5032_Assignment.Controllers { } } - // GET: Appointments/Edit/5 - public ActionResult Edit(int id) { + // GET: Appointments/UploadImage/uuid + public ActionResult UploadImage(string id) { + // Check login + if (Request.Cookies["psg_auth_token"] == null) { + // Redirect to home page + return RedirectToAction("Index"); + } + var user = psgCredentialVerify(Request.Cookies["psg_auth_token"].Value); + if (user == null) { + // Redirect to home page + Response.Cookies["psg_auth_token"].Expires = DateTime.Now.AddDays(-1); + return RedirectToAction("Index"); + } + var userProfile = loginInfo(user); + if (userProfile == null) { + // Redirect to home page, and remove cookies + Response.Cookies["psg_auth_token"].Expires = DateTime.Now.AddDays(-1); + return RedirectToAction("Index"); + } + // Detect user role + ViewBag.role = db.Users.Find(userProfile.uuid).role; + if (userProfile.role != 2) { + TempData["tip"] = "This operation is not allowed."; + return Redirect("/Appointments/Index"); + } + + // Check if the appointment is belong to the doctor + var appointment = db.Appointments.Find(id); + if (appointment == null) { + TempData["tip"] = "The appointment does not exist."; + return Redirect("/Appointments/Index"); + } + if (appointment.responsibleBy != userProfile.uuid) { + TempData["tip"] = "The appointment does not exist."; + return Redirect("/Appointments/Index"); + } + + // Check status == 1 + if (appointment.status != 1) { + TempData["tip"] = "Operation invalid"; + return Redirect("/Appointments/Index"); + } + + ViewBag.appointment = appointment; + ViewBag.patient = db.Users.Find(appointment.patient); return View(); } - // POST: Appointments/Edit/5 [HttpPost] - public ActionResult Edit(int id, FormCollection collection) { + public async Task UploadImage(HttpPostedFileBase image, string appointmentUuid) { try { - // TODO: Add update logic here + // Check login + if (Request.Cookies["psg_auth_token"] == null) { + // Redirect to home page + return RedirectToAction("Index"); + } + var user = psgCredentialVerify(Request.Cookies["psg_auth_token"].Value); + if (user == null) { + // Redirect to home page + Response.Cookies["psg_auth_token"].Expires = DateTime.Now.AddDays(-1); + return RedirectToAction("Index"); + } + var userProfile = loginInfo(user); + if (userProfile == null) { + // Redirect to home page, and remove cookies + Response.Cookies["psg_auth_token"].Expires = DateTime.Now.AddDays(-1); + return RedirectToAction("Index"); + } + // Detect user role + ViewBag.role = db.Users.Find(userProfile.uuid).role; + if (userProfile.role != 2) { + TempData["tip"] = "This operation is not allowed."; + return Redirect("/Appointments/Index"); + } - return RedirectToAction("Index"); - } - catch { - return View(); - } - } + // Check the appointment exist & status == 1 & responsibleBy == doctor + var appointment = db.Appointments.Find(appointmentUuid); + if (appointment == null) { + TempData["tip"] = "The appointment does not exist."; + return Redirect("/Appointments/Index"); + } + if (appointment.responsibleBy != userProfile.uuid) { + TempData["tip"] = "The appointment does not exist."; + return Redirect("/Appointments/Index"); + } + if (appointment.status != 1) { + TempData["tip"] = "Operation invalid"; + return Redirect("/Appointments/Index"); + } - // GET: Appointments/Delete/5 - public ActionResult Delete(int id) { - return View(); - } + // check uploaded file + if (image == null) { + ViewBag.tip = "Please upload a file"; + ViewBag.appointment = appointment; + ViewBag.patient = db.Users.Find(appointment.patient); + return View(); + } - // POST: Appointments/Delete/5 - [HttpPost] - public ActionResult Delete(int id, FormCollection collection) { - try { - // TODO: Add delete logic here + // check format: png, jpg, jpeg + string[] formats = new string[] { ".png", ".jpg", ".jpeg" }; + string extension = Path.GetExtension(image.FileName); + if (!formats.Contains(extension)) { + ViewBag.tip = "Please upload a png, jpg or jpeg file"; + ViewBag.appointment = appointment; + ViewBag.patient = db.Users.Find(appointment.patient); + return View(); + } - return RedirectToAction("Index"); - } - catch { - return View(); + // save file + var fileId = Guid.NewGuid().ToString(); + var fileName = fileId + extension; + var filePath = Path.Combine(Server.MapPath("~/App_Data/upload_images"), fileName); + image.SaveAs(filePath); + + // Create image entity to database + var appointmentId = appointment.uuid; + var imageId = Guid.NewGuid().ToString(); + var patientUuid = appointment.patient; + var dbImage = new Images { + uuid = imageId, + appointment = appointmentId, + patient = patientUuid, + responsibleBy = userProfile.uuid, + createdAt = DateTime.Now, + file = fileName, + status = 0, + }; + // Change appointment status to 2 + appointment.status = 2; + db.Entry(appointment).State = EntityState.Modified; + db.SaveChanges(); + + // Find patient email from Passage service + var credential = db.Credentials.Where(res => (res.user == patientUuid) && (res.provider == 0)); + Trace.WriteLine(credential.First().uniqueIdCode); + var user_id = credential.First().uniqueIdCode; + var app_id = "ZHM5whW5xsZEczTn2loffzjN"; + RestClient passageClient = new RestClient(new RestClientOptions($"https://api.passage.id/v1/apps/{app_id}")); + passageClient.AddDefaultHeader("Authorization", "Bearer vF4ch1wUf8.1cqOms9JMmUbqMGohlkJLzGDVlbF51D03fJnLfxwkn8kyAaVVjfvySufW9vXb3p3"); + var psgRequest = new RestRequest($"users/{user_id}", Method.Get); + + // Send request + var passageResponse = await passageClient.ExecuteAsync(psgRequest); + Trace.WriteLine(passageResponse.Content); + + // Transfer response + var passageResponseJson = JsonConvert.DeserializeObject(passageResponse.Content); + var patientEmail = passageResponseJson.User.Email; + + // Send attached email with mailgun + var doctorName = userProfile.displayName; + var patient = db.Users.Find(patientUuid); + RestClient client = new RestClient(new RestClientOptions("https://api.mailgun.net/v3/test.astrian.moe") { + Authenticator = new HttpBasicAuthenticator("api", "365900a7818241eafcbbf82e59cf99e8-5465e583-b4966e64"), + }); + var request = new RestRequest("messages", Method.Post); + request.AddParameter("from", "Xpectrum "); + request.AddParameter("to", patientEmail); + request.AddParameter("subject", "Xpectrum: New image available"); + request.AddParameter("text", $"Hi {patient.displayName},\n\nDr. {doctorName} has uploaded a new image for you.\n\nPlease check the attachment.\n\nBest regards,\nXpectrum"); + request.AddFile("attachment", filePath); + + // Send request + var response = await client.ExecuteAsync(request); + Trace.WriteLine(response.Content); + + TempData["tip"] = "The image has been attached to the appointment."; + return Redirect("/Appointments/Index"); + } catch { + TempData["tip"] = "System error"; + return Redirect("/Appointments/Index"); } } } diff --git a/FIT5032-Assignment/FIT5032-Assignment.csproj b/FIT5032-Assignment/FIT5032-Assignment.csproj index a8b4be2..3bfe2bc 100644 --- a/FIT5032-Assignment/FIT5032-Assignment.csproj +++ b/FIT5032-Assignment/FIT5032-Assignment.csproj @@ -322,9 +322,10 @@ - + + diff --git a/FIT5032-Assignment/Views/Appointments/Index.cshtml b/FIT5032-Assignment/Views/Appointments/Index.cshtml index d0b3c36..c562a18 100644 --- a/FIT5032-Assignment/Views/Appointments/Index.cshtml +++ b/FIT5032-Assignment/Views/Appointments/Index.cshtml @@ -88,7 +88,7 @@ Approve Cancel } else if (item.Item1.status == 1) { - Upload Image + Upload Image } diff --git a/FIT5032-Assignment/Views/Appointments/UploadImage.cshtml b/FIT5032-Assignment/Views/Appointments/UploadImage.cshtml new file mode 100644 index 0000000..5a9fc73 --- /dev/null +++ b/FIT5032-Assignment/Views/Appointments/UploadImage.cshtml @@ -0,0 +1,28 @@ +@model FIT5032_Assignment.Models.ImageUploadForm +@{ + Layout = "~/Views/Shared/_Layout.cshtml"; +} + +@if (ViewBag.tip != null) { + +} + +

Upload image

+ +
+ +
You are about to upload the image for the appointment booked by @ViewBag.patient.displayName in @ViewBag.appointment.appointmentDate
+
+ +
+ +
+
+ +
+ +@section Scripts { + @Scripts.Render("~/bundles/jqueryval") +} diff --git a/FIT5032-Assignment/Views/Home/ImageUpload.cshtml b/FIT5032-Assignment/Views/Home/ImageUpload.cshtml index dab88e7..cdef834 100644 --- a/FIT5032-Assignment/Views/Home/ImageUpload.cshtml +++ b/FIT5032-Assignment/Views/Home/ImageUpload.cshtml @@ -4,38 +4,11 @@ } -@using (Html.BeginForm("ImageUpload", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" })) -{ - @Html.AntiForgeryToken() - -
-

Upload Image

-
- @Html.ValidationSummary(true, "", new { @class = "text-danger" }) -
- @Html.LabelFor(model => model.patientEmail, htmlAttributes: new { @class = "control-label col-md-2" }) -
- @Html.EditorFor(model => model.patientEmail, new { htmlAttributes = new { @class = "form-control" } }) - @Html.ValidationMessageFor(model => model.patientEmail, "", new { @class = "text-danger" }) -
-
+

Upload image

-
- @Html.LabelFor(model => model.imageFile, htmlAttributes: new { @class = "control-label col-md-2" }) -
- - @Html.ValidationMessageFor(model => model.imageFile, "", new { @class = "text-danger" }) -
-
- - -
-
- -
-
-
-} +
+ @ViewBag.appointment +
@section Scripts { @Scripts.Render("~/bundles/jqueryval")