Book appointment
This commit is contained in:
parent
a107386ecd
commit
c3c09f8966
|
@ -22,6 +22,12 @@ namespace FIT5032_Assignment {
|
||||||
url: "{controller}/{action}/{id}",
|
url: "{controller}/{action}/{id}",
|
||||||
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
|
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
routes.MapRoute(
|
||||||
|
name: "Appointments",
|
||||||
|
url: "Appointments",
|
||||||
|
defaults: new { controller = "Appointments", action = "Index", id = UrlParameter.Optional }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,93 @@ using System.Web.Mvc;
|
||||||
using FIT5032_Assignment.Models;
|
using FIT5032_Assignment.Models;
|
||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Text;
|
||||||
|
using Org.BouncyCastle.Crypto;
|
||||||
|
using Org.BouncyCastle.OpenSsl;
|
||||||
|
using Org.BouncyCastle.Security;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FIT5032_Assignment.Controllers {
|
namespace FIT5032_Assignment.Controllers {
|
||||||
public class AppointmentsController : Controller {
|
public class AppointmentsController : Controller {
|
||||||
private Database1Entities db = new Database1Entities();
|
private Database1Entities db = new Database1Entities();
|
||||||
|
|
||||||
|
// Login check
|
||||||
|
private static RsaSecurityKey LoadRsaSecurityKeyFromPem(string pem) {
|
||||||
|
TextReader textReader = new StringReader(pem);
|
||||||
|
PemReader pemReader = new PemReader(textReader);
|
||||||
|
AsymmetricKeyParameter keyParameter = (AsymmetricKeyParameter)pemReader.ReadObject();
|
||||||
|
|
||||||
|
RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters((Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keyParameter);
|
||||||
|
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
|
||||||
|
rsa.ImportParameters(rsaParameters);
|
||||||
|
|
||||||
|
return new RsaSecurityKey(rsa);
|
||||||
|
}
|
||||||
|
private String psgCredentialVerify(string token) {
|
||||||
|
|
||||||
|
var jwtHandler = new JwtSecurityTokenHandler();
|
||||||
|
var jwtToken = jwtHandler.ReadJwtToken(token);
|
||||||
|
|
||||||
|
string base64Publickey = "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQTRUWEQwVEh4NnJjNXlQcXM0Skw5M01nVEgvTS95Z2s3V1pYWWsrS01XTTA0bDdzM3owRlMKODlDRE56SFJkbVpJb3RCbDgrcUJ5TUwvck5VcUhXMnJ1Uzg0dmxFaWdza2djK2RsaitCZXFsaGsySFRpQitpegpQcGdCU1FJc2YrZjdSU3dkYktFS2hRQm1La3MxVGF4YWNDUndPVWJKT1VQbjJXZmhVSHhRd0FwZGNCQWdNdHVNCld3QzJZRThGblFRZDhxc3dMTTBGQWhoSzUrdXRXY0s0bHdCVlFxUGJRaUJZYnZmWXkwYVF6UFB2V2NMR1JvR00KUVA1b1JCTmRuRzQ4Sm9Eb2tCSEJkbCt4RzM1L1U2N1BvejFKY0VVSnpWTHdIUFNHa0xyRU1OYlFrbnJSK2tHZwpnS1dWNFpvYWVOSHZVeFE3YVg3SElFMlc1UnIwRmxGUG1RSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K";
|
||||||
|
RsaSecurityKey rsaKey = LoadRsaSecurityKeyFromPem(Encoding.UTF8.GetString(Convert.FromBase64String(base64Publickey)));
|
||||||
|
// Valid time 3600s
|
||||||
|
var validationParameters = new TokenValidationParameters() {
|
||||||
|
ValidIssuer = "https://auth.passage.id/v1/apps/ZHM5whW5xsZEczTn2loffzjN",
|
||||||
|
ValidateAudience = false,
|
||||||
|
IssuerSigningKey = rsaKey,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ClockSkew = TimeSpan.FromSeconds(3600)
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
var claimsPrincipal = jwtHandler.ValidateToken(token, validationParameters, out var rawValidatedToken);
|
||||||
|
} catch (SecurityTokenExpiredException) {
|
||||||
|
Trace.WriteLine("Token has expired");
|
||||||
|
return null;
|
||||||
|
} catch (SecurityTokenInvalidSignatureException) {
|
||||||
|
Trace.WriteLine("Token has invalid signature");
|
||||||
|
return null;
|
||||||
|
} catch (SecurityTokenInvalidIssuerException) {
|
||||||
|
Trace.WriteLine("Token has invalid issuer");
|
||||||
|
return null;
|
||||||
|
} catch (SecurityTokenInvalidAudienceException) {
|
||||||
|
Trace.WriteLine("Token has invalid audience");
|
||||||
|
return null;
|
||||||
|
} catch (SecurityTokenValidationException) {
|
||||||
|
Trace.WriteLine("Token failed validation");
|
||||||
|
return null;
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
Trace.WriteLine("Token was empty or null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string sub = jwtToken.Claims.First(claim => claim.Type == "sub").Value;
|
||||||
|
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
private Users loginInfo(string user) {
|
||||||
|
var db = new Database1Entities();
|
||||||
|
var credential = db.Credentials.Where(res => (res.uniqueIdCode == user) && (res.provider == 0));
|
||||||
|
if (credential.Count() == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
var userUuid = credential.First().user;
|
||||||
|
var dbUser = db.Users.Where(res => res.uuid == userUuid);
|
||||||
|
if (dbUser.Count() == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return dbUser.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GET: Appointments
|
// GET: Appointments
|
||||||
public ActionResult Index() {
|
public ActionResult Index() {
|
||||||
|
ViewBag.tip = TempData["tip"];
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +104,10 @@ namespace FIT5032_Assignment.Controllers {
|
||||||
|
|
||||||
// GET: Appointments/Create
|
// GET: Appointments/Create
|
||||||
public ActionResult Create(string id) {
|
public ActionResult Create(string id) {
|
||||||
|
if (Request.Cookies["psg_auth_token"] == null) {
|
||||||
|
// Redirect to home page
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
// Pass a dropdown list for all doctors
|
// Pass a dropdown list for all doctors
|
||||||
List<Doctors> doctors = db.Doctors.ToList();
|
List<Doctors> doctors = db.Doctors.ToList();
|
||||||
|
@ -44,15 +129,75 @@ namespace FIT5032_Assignment.Controllers {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// POST: Appointments/Create
|
// POST: Appointments/Create/doctorId
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public ActionResult Create(FormCollection collection) {
|
public ActionResult Create(FormCollection collection) {
|
||||||
try {
|
try {
|
||||||
// TODO: Add insert logic here
|
// TODO: Add insert logic here
|
||||||
|
Trace.WriteLine(collection["doctorUuid"]);
|
||||||
|
|
||||||
return RedirectToAction("Index");
|
// Verify login
|
||||||
|
if (Request.Cookies["psg_auth_token"] == null) {
|
||||||
|
// Redirect to home page
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
|
Trace.WriteLine("User has cookie");
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
Trace.WriteLine("User has login");
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
Trace.WriteLine("User login available");
|
||||||
|
// Detect if user logined is patient
|
||||||
|
if (userProfile.role != 1) {
|
||||||
|
// Redirect to home page
|
||||||
|
return Redirect("/Appointments/Index");
|
||||||
|
}
|
||||||
|
Trace.WriteLine("User is patient");
|
||||||
|
|
||||||
|
// Transfer MM/dd/yyyy (18/10/2023) to C# DateTime
|
||||||
|
Trace.WriteLine(collection["appointmentDate"]);
|
||||||
|
DateTime date = DateTime.ParseExact(collection["appointmentDate"], "dd/MM/yyyy", CultureInfo.InvariantCulture);
|
||||||
|
Trace.WriteLine(date);
|
||||||
|
|
||||||
|
// The date cannot be earlier than today 0:00
|
||||||
|
|
||||||
|
if (date < DateTime.Today) {
|
||||||
|
ViewBag.tip = "The date cannot be earlier than today.";
|
||||||
|
ViewBag.doctorId = collection["doctorUuid"];
|
||||||
|
ViewBag.doctorUser = db.Users.Find(collection["doctorUuid"]);
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create appointment
|
||||||
|
var uuid = Guid.NewGuid().ToString();
|
||||||
|
Appointments appointment = new Appointments {
|
||||||
|
uuid = uuid,
|
||||||
|
patient = userProfile.uuid,
|
||||||
|
responsibleBy = collection["doctorUuid"],
|
||||||
|
createdAt = DateTime.Now,
|
||||||
|
appointmentDate = date,
|
||||||
|
status = 0,
|
||||||
|
createdBy = 0
|
||||||
|
};
|
||||||
|
db.Appointments.Add(appointment);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
TempData["tip"] = "The appointment has been booked.";
|
||||||
|
return Redirect("/Appointments/Index");
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
|
ViewBag.tip = "System error";
|
||||||
|
ViewBag.doctorId = collection["doctorUuid"];
|
||||||
|
ViewBag.doctorUser = db.Users.Find(collection["doctorUuid"]);
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace FIT5032_Assignment.Controllers {
|
||||||
public DbSet<Sessions> Sessions { get; set; }
|
public DbSet<Sessions> Sessions { get; set; }
|
||||||
public DbSet<Patients> Patients { get; set; }
|
public DbSet<Patients> Patients { get; set; }
|
||||||
public DbSet<Doctors> Doctors { get; set; }
|
public DbSet<Doctors> Doctors { get; set; }
|
||||||
|
public DbSet<Appointments> Appointments { get; set; }
|
||||||
}
|
}
|
||||||
public class HomeController : Controller {
|
public class HomeController : Controller {
|
||||||
public static string GetMd5Hash(string input) {
|
public static string GetMd5Hash(string input) {
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (ViewBag.tip != null) {
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
@ViewBag.tip
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<h2>Book an appointment</h2>
|
<h2>Book an appointment</h2>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -32,11 +38,12 @@
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
<h3>Book an appointment with @ViewBag.doctorUser.displayName</h3>
|
<h3>Book an appointment with @ViewBag.doctorUser.displayName</h3>
|
||||||
<form>
|
<form method="post">
|
||||||
|
<input type="hidden" name="doctorUuid" value="@ViewBag.doctorUser.uuid" />
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="datepicker">Select the appointment date</label>
|
<label for="datepicker">Select the appointment date</label>
|
||||||
<div class='input-group'>
|
<div class='input-group'>
|
||||||
<input data-provide="datepicker" id="datepicker" class="form-control" />
|
<input data-provide="datepicker" id="datepicker" class="form-control" name="appointmentDate" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (ViewBag.tip != null) {
|
||||||
|
<div class="alert alert-success" role="alert">
|
||||||
|
@ViewBag.tip
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<h2>Appointments</h2>
|
<h2>Appointments</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user