diff --git a/HealthCareABApi/HealthCareABApi.csproj b/HealthCareABApi/HealthCareABApi.csproj
index 48d7652..5770088 100644
--- a/HealthCareABApi/HealthCareABApi.csproj
+++ b/HealthCareABApi/HealthCareABApi.csproj
@@ -9,12 +9,14 @@
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/HealthCareABApi/Models/SmtpSettings.cs b/HealthCareABApi/Models/SmtpSettings.cs
new file mode 100644
index 0000000..1581a4a
--- /dev/null
+++ b/HealthCareABApi/Models/SmtpSettings.cs
@@ -0,0 +1,12 @@
+namespace HealthCareABApi.Models
+{
+ public class SmtpSettings
+ {
+ public string Server { get; set; }
+ public int Port { get; set; }
+ public string Username { get; set; }
+ public string Password { get; set; }
+ public string FromName { get; set; }
+ public string FromEmail { get; set; }
+ }
+}
diff --git a/HealthCareABApi/Program.cs b/HealthCareABApi/Program.cs
index 295fd8f..5941fbd 100644
--- a/HealthCareABApi/Program.cs
+++ b/HealthCareABApi/Program.cs
@@ -8,6 +8,8 @@
using Microsoft.EntityFrameworkCore;
using HealthCareABApi.Repositories.Interfaces;
using HealthCareABApi.BackgroundJobs;
+using HealthCareABApi.Models;
+using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
@@ -15,6 +17,8 @@
builder.Services.AddDbContext(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
+builder.Services.Configure(builder.Configuration.GetSection("SmtpSettings"));
+
// Register repositories
builder.Services.AddScoped();
builder.Services.AddScoped();
@@ -26,6 +30,7 @@
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
+builder.Services.AddScoped();
// Register background jobs
builder.Services.AddHostedService();
diff --git a/HealthCareABApi/Repositories/Implementations/AppointmentRepository.cs b/HealthCareABApi/Repositories/Implementations/AppointmentRepository.cs
index dc10d19..af1d0bf 100644
--- a/HealthCareABApi/Repositories/Implementations/AppointmentRepository.cs
+++ b/HealthCareABApi/Repositories/Implementations/AppointmentRepository.cs
@@ -1,25 +1,28 @@
-using System;
-using HealthCareABApi.Models;
-using HealthCareABApi.Repositories.Data;
-using Microsoft.EntityFrameworkCore;
-
-namespace HealthCareABApi.Repositories.Implementations
-{
- public class AppointmentRepository : IAppointmentRepository
- {
- private readonly HealthCareDbContext _Dbcontext;
-
- public AppointmentRepository(HealthCareDbContext context)
- {
- _Dbcontext = context;
- }
-
- public async Task> GetAllAsync()
- {
- return await _Dbcontext.Appointment
- .Include(a => a.Patient)
- .Include(a => a.Caregiver)
- .ToListAsync();
+using System;
+using HealthCareABApi.Models;
+using HealthCareABApi.Repositories.Data;
+using HealthCareABApi.Repositories.Interfaces;
+using Microsoft.EntityFrameworkCore;
+
+namespace HealthCareABApi.Repositories.Implementations
+{
+ public class AppointmentRepository : IAppointmentRepository
+ {
+ private readonly HealthCareDbContext _Dbcontext;
+ private readonly IEmailService _emailService;
+
+ public AppointmentRepository(HealthCareDbContext context, IEmailService emailService)
+ {
+ _Dbcontext = context;
+ _emailService = emailService;
+ }
+
+ public async Task> GetAllAsync()
+ {
+ return await _Dbcontext.Appointment
+ .Include(a => a.Patient)
+ .Include(a => a.Caregiver)
+ .ToListAsync();
}
public async Task GetByIdAsync(int id)
@@ -39,76 +42,136 @@ public async Task GetByPatientAndTimeAsync(int patientId, DateTime
a.PatientId == patientId &&
EF.Functions.DateDiffSecond(a.DateTime, localTime) == 0 && // Ignorerar millisekunder i databasen och kollar tiden på sekundnivå
a.Status == AppointmentStatus.Scheduled);
- }
-
+ }
+
public async Task> GetCompletedByUserIdAsync(int userId)
- {
- return await _Dbcontext.Appointment
- .Include(x => x.Caregiver)
- .Include(x => x.Patient)
+ {
+ return await _Dbcontext.Appointment
+ .Include(x => x.Caregiver)
+ .Include(x => x.Patient)
.Where(x => x.PatientId == userId && x.Status == AppointmentStatus.Completed)
- .ToListAsync();
- }
+ .ToListAsync();
+ }
+
+ public async Task CreateAsync(Appointment appointment)
+ {
+ if (appointment == null)
+ {
+ throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
+ }
+
+ try
+ {
+ var availability = await _Dbcontext.Availability
+ .FirstOrDefaultAsync(a =>
+ a.Caregiver.Id == appointment.CaregiverId &&
+ a.StartTime <= appointment.DateTime &&
+ a.EndTime > appointment.DateTime &&
+ !a.IsBooked);
+
+ var patient = await _Dbcontext.User.Where(x => x.Id == appointment.PatientId).FirstOrDefaultAsync();
+ var careGiver = await _Dbcontext.User.Where(x => x.Id == appointment.CaregiverId).FirstOrDefaultAsync();
+
+ if (availability == null)
+ {
+ throw new InvalidOperationException("No available slot for this time.");
+ }
+
+ availability.IsBooked = true;
+ availability.Appointment = appointment;
+
+ await _Dbcontext.Appointment.AddAsync(appointment);
+
+ await _Dbcontext.SaveChangesAsync();
+ //await _Dbcontext.Appointment.AddAsync(appointment);
+ //await _Dbcontext.SaveChangesAsync();
+
+ var body = $@"
+ Hello {appointment.Patient.Firstname},
+
+ Your appointment has been successfully scheduled:
+
+ Patient Name: {patient.Firstname} {patient.Lastname}
+ Appointment Time: {appointment.DateTime.ToString("f")}
+ Caregiver: {careGiver.Firstname} {careGiver.Lastname}
+
+ If you have any questions, please contact us at support@healthCareAbExample.com
+
+ The Healthcare AB Team
+ ";
+
+
+ await _emailService.SendEmailAsync(patient.Email, "Appointment Booked", body, $"{patient.Firstname} {patient.Lastname}");
+
+ }
+ catch (DbUpdateException ex)
+ {
+ throw new InvalidOperationException("Database error while creating appointment", ex);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Error creating new appointment", ex);
+ }
+ }
+
+ public async Task UpdateAsync(int id, Appointment appointment)
+ {
+ var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).Include(x => x.Patient).Include(x => x.Caregiver).FirstOrDefaultAsync();
+
+ if (exist == null)
+ {
+ return false;
+ }
+
+
+ _Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
+ await _Dbcontext.SaveChangesAsync();
+
+ var body = $@"
+ Hello {appointment.Patient.Firstname},
- public async Task CreateAsync(Appointment appointment)
- {
- if (appointment == null)
- {
- throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
- }
+ Your appointment has been successfully Updated:
- try
- {
- var availability = await _Dbcontext.Availability
- .FirstOrDefaultAsync(a =>
- a.Caregiver.Id == appointment.CaregiverId &&
- a.StartTime <= appointment.DateTime &&
- a.EndTime > appointment.DateTime &&
- !a.IsBooked);
+ Patient Name: {appointment.Patient.Firstname} {appointment.Patient.Lastname}
+ Appointment Time: {appointment.DateTime.ToString("f")}
+ Caregiver: {appointment.Caregiver.Firstname} {appointment.Caregiver.Lastname}
- if (availability == null)
- {
- throw new InvalidOperationException("No available slot for this time.");
- }
+ If you have any questions, please contact us at support@healthCareAbExample.com
- availability.IsBooked = true;
- availability.Appointment = appointment;
+ The Healthcare AB Team
+ ";
- await _Dbcontext.Appointment.AddAsync(appointment);
- await _Dbcontext.SaveChangesAsync();
- }
- catch (DbUpdateException ex)
- {
- throw new InvalidOperationException("Database error while creating appointment", ex);
- }
- catch (Exception ex)
+ await _emailService.SendEmailAsync(appointment.Patient.Email, "Appointment Updated", body, $"{appointment.Patient.Firstname} {appointment.Patient.Lastname}");
+
+ return true;
+ }
+
+ public async Task DeleteAsync(int id)
+ {
+ using (var transaction = await _Dbcontext.Database.BeginTransactionAsync())
{
- throw new InvalidOperationException("Error creating new appointment", ex);
- }
- }
- public async Task UpdateAsync(int id, Appointment appointment)
- {
- var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).FirstOrDefaultAsync();
+ try
+ {
+ var appointment = await _Dbcontext.Appointment.Where(x => x.Id == id).Include(x => x.Patient).Include(x => x.Caregiver).FirstOrDefaultAsync();
- if (exist == null)
- {
- return false;
- }
+ var body = $@"
+ Hello {appointment.Patient.Firstname},
- _Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
- await _Dbcontext.SaveChangesAsync();
- return true;
- }
+ Your appointment have been deleted:
- public async Task DeleteAsync(int id)
- {
- using (var transaction = await _Dbcontext.Database.BeginTransactionAsync())
- {
+ Patient Name: {appointment.Patient.Firstname} {appointment.Patient.Lastname}
+ Appointment Time: {appointment.DateTime.ToString("f")}
+ Caregiver: {appointment.Caregiver.Firstname} {appointment.Caregiver.Lastname}
- try
- {
+ If you have any questions, please contact us at support@healthCareAbExample.com
+
+ The Healthcare AB Team
+ ";
+
+ await _emailService.SendEmailAsync(appointment.Patient.Email, "Appointment Deleted", body, $"{appointment.Patient.Firstname} {appointment.Patient.Lastname}");
+
var relatedAvailability = await _Dbcontext.Availability
.Where(a => a.AppointmentId == id)
.FirstOrDefaultAsync();
@@ -161,4 +224,4 @@ public async Task> GetScheduledAppointmentsAsync(int us
}
}
}
-
+
diff --git a/HealthCareABApi/Repositories/Interfaces/IEmailService.cs b/HealthCareABApi/Repositories/Interfaces/IEmailService.cs
new file mode 100644
index 0000000..b39c6aa
--- /dev/null
+++ b/HealthCareABApi/Repositories/Interfaces/IEmailService.cs
@@ -0,0 +1,7 @@
+namespace HealthCareABApi.Repositories.Interfaces
+{
+ public interface IEmailService
+ {
+ Task SendEmailAsync(string toEmail, string subject, string body, string name);
+ }
+}
diff --git a/HealthCareABApi/Services/AppointmentService.cs b/HealthCareABApi/Services/AppointmentService.cs
index c203eed..9d371cf 100644
--- a/HealthCareABApi/Services/AppointmentService.cs
+++ b/HealthCareABApi/Services/AppointmentService.cs
@@ -14,7 +14,6 @@ public AppointmentService(IAppointmentRepository appointmentRepository, IAvailab
{
_appointmentRepository = appointmentRepository;
_availabilityRepository = availabilityRepository;
-
}
public async Task CreateAsync(CreateAppointmentDTO dto)
diff --git a/HealthCareABApi/Services/AvailabilityService.cs b/HealthCareABApi/Services/AvailabilityService.cs
index b3201ad..d618d7b 100644
--- a/HealthCareABApi/Services/AvailabilityService.cs
+++ b/HealthCareABApi/Services/AvailabilityService.cs
@@ -11,11 +11,13 @@ namespace HealthCareABApi.Services
public class AvailabilityService : IAvailabilityService
{
private readonly IAvailabilityRepository _availabilityRepository;
+ private readonly IAppointmentRepository _appointmentRepository;
private readonly HealthCareDbContext _Dbcontext;
- public AvailabilityService(IAvailabilityRepository availabilityRepository, HealthCareDbContext context)
+ public AvailabilityService(IAvailabilityRepository availabilityRepository, HealthCareDbContext context, IAppointmentRepository appointmentRepository)
{
_availabilityRepository = availabilityRepository;
+ _appointmentRepository = appointmentRepository;
_Dbcontext = context;
}
@@ -175,7 +177,7 @@ public async Task DeleteAsync(int id)
if (availability.AppointmentId.HasValue)
{
- _Dbcontext.Appointment.Remove(availability.Appointment);
+ await _appointmentRepository.DeleteAsync(availability.AppointmentId.Value);
}
_Dbcontext.Availability.Remove(availability);
diff --git a/HealthCareABApi/Services/EmailService.cs b/HealthCareABApi/Services/EmailService.cs
new file mode 100644
index 0000000..df9451e
--- /dev/null
+++ b/HealthCareABApi/Services/EmailService.cs
@@ -0,0 +1,46 @@
+using MimeKit;
+using MailKit.Security;
+using Microsoft.Extensions.Options;
+using HealthCareABApi.Repositories.Interfaces;
+using MailKit.Net.Smtp;
+using HealthCareABApi.Models;
+namespace HealthCareABApi.Services
+{
+ public class EmailService : IEmailService
+ {
+ private readonly SmtpSettings _smtpSettings;
+
+ public EmailService(IOptions smtpSettings)
+ {
+ _smtpSettings = smtpSettings.Value;
+ }
+
+ public async Task SendEmailAsync(string toEmail, string subject, string body, string name)
+ {
+ var message = new MimeMessage();
+ message.From.Add(new MailboxAddress(_smtpSettings.FromName, _smtpSettings.FromEmail));
+ message.To.Add(new MailboxAddress(name, toEmail));
+ message.Subject = subject;
+
+ var bodyBuilder = new BodyBuilder
+ {
+ HtmlBody = body
+ };
+ message.Body = bodyBuilder.ToMessageBody();
+ try
+ {
+ using (var client = new SmtpClient())
+ {
+ await client.ConnectAsync(_smtpSettings.Server, _smtpSettings.Port, SecureSocketOptions.StartTls);
+ await client.AuthenticateAsync(_smtpSettings.Username, _smtpSettings.Password);
+ await client.SendAsync(message);
+ await client.DisconnectAsync(true);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Failed to send email: {ex.Message}", ex);
+ }
+ }
+ }
+}
diff --git a/HealthCareABApi/appsettings.json b/HealthCareABApi/appsettings.json
index 262b9f0..7b37f94 100644
--- a/HealthCareABApi/appsettings.json
+++ b/HealthCareABApi/appsettings.json
@@ -14,5 +14,13 @@
"Microsoft.AspNetCore": "Warning"
}
},
+ "SmtpSettings": {
+ "Server": "smtp.gmail.com",
+ "Port": 587,
+ "Username": "axel.calas.dev@gmail.com",
+ "Password": "ubiq xspz pxns ogmw",
+ "FromName": "HealthCare AB",
+ "FromEmail": "noReply@healthcare.com"
+ },
"AllowedHosts": "*"
}